Line data Source code
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 46005 : static int OGRKMLDriverIdentify(GDALOpenInfo *poOpenInfo) 30 : 31 : { 32 46005 : if (poOpenInfo->fpL == nullptr) 33 42861 : return FALSE; 34 : 35 3144 : return strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader), "<kml") != 36 6238 : nullptr || 37 3094 : strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader), 38 3144 : "<kml:kml") != nullptr; 39 : } 40 : 41 : /************************************************************************/ 42 : /* Open() */ 43 : /************************************************************************/ 44 : 45 25 : static GDALDataset *OGRKMLDriverOpen(GDALOpenInfo *poOpenInfo) 46 : 47 : { 48 25 : if (poOpenInfo->eAccess == GA_Update) 49 0 : return nullptr; 50 : 51 25 : if (!OGRKMLDriverIdentify(poOpenInfo)) 52 0 : return nullptr; 53 : 54 : #ifdef HAVE_EXPAT 55 25 : OGRKMLDataSource *poDS = new OGRKMLDataSource(); 56 : 57 25 : if (poDS->Open(poOpenInfo->pszFilename, TRUE)) 58 : { 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 : } 70 : else 71 : { 72 2 : delete poDS; 73 2 : poDS = nullptr; 74 : } 75 : 76 25 : return poDS; 77 : #else 78 : return nullptr; 79 : #endif 80 : } 81 : 82 : /************************************************************************/ 83 : /* Create() */ 84 : /************************************************************************/ 85 : 86 42 : static GDALDataset *OGRKMLDriverCreate(const char *pszName, int /* nBands */, 87 : int /* nXSize */, int /* nYSize */, 88 : GDALDataType /* eDT */, 89 : char **papszOptions) 90 : { 91 42 : CPLAssert(nullptr != pszName); 92 42 : CPLDebug("KML", "Attempt to create: %s", pszName); 93 : 94 42 : OGRKMLDataSource *poDS = new OGRKMLDataSource(); 95 : 96 42 : if (!poDS->Create(pszName, papszOptions)) 97 : { 98 1 : delete poDS; 99 1 : poDS = nullptr; 100 : } 101 : 102 42 : return poDS; 103 : } 104 : 105 : /************************************************************************/ 106 : /* RegisterOGRKML() */ 107 : /************************************************************************/ 108 : 109 1595 : void RegisterOGRKML() 110 : { 111 1595 : if (GDALGetDriverByName("KML") != nullptr) 112 302 : return; 113 : 114 1293 : GDALDriver *poDriver = new GDALDriver(); 115 : 116 1293 : poDriver->SetDescription("KML"); 117 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 118 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 119 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 120 1293 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 121 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 122 1293 : "Keyhole Markup Language (KML)"); 123 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kml"); 124 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/kml.html"); 125 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 126 : 127 1293 : poDriver->SetMetadataItem( 128 : GDAL_DMD_CREATIONOPTIONLIST, 129 : "<CreationOptionList>" 130 : " <Option name='DOCUMENT_ID' type='string' description='Id of the " 131 : "root <Document> node' default='root_doc'/>" 132 : " <Option name='GPX_USE_EXTENSIONS' type='boolean' " 133 : "description='Whether to write non-GPX attributes in an " 134 : "<extensions> tag' default='NO'/>" 135 : " <Option name='NameField' type='string' description='Field to use to " 136 : "fill the KML <name> element' default='Name'/>" 137 : " <Option name='DescriptionField' type='string' description='Field to " 138 : "use to fill the KML <description> element' " 139 : "default='Description'/>" 140 : " <Option name='AltitudeMode' type='string-select' description='Value " 141 : "of the <AltitudeMode> element for 3D geometries'>" 142 : " <Value>clampToGround</Value>" 143 : " <Value>relativeToGround</Value>" 144 : " <Value>absolute</Value>" 145 : " </Option>" 146 1293 : "</CreationOptionList>"); 147 : 148 1293 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, 149 1293 : "<LayerCreationOptionList/>"); 150 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 151 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, 152 1293 : "Integer Real String"); 153 1293 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES"); 154 1293 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_WRITE, "YES"); 155 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 156 : 157 1293 : poDriver->pfnOpen = OGRKMLDriverOpen; 158 1293 : poDriver->pfnIdentify = OGRKMLDriverIdentify; 159 1293 : poDriver->pfnCreate = OGRKMLDriverCreate; 160 : 161 1293 : GetGDALDriverManager()->RegisterDriver(poDriver); 162 : }