Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: LV BAG Translator 4 : * Purpose: Implements OGRLVBAGDriver. 5 : * Author: Laixer B.V., info at laixer dot com 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2020, Laixer B.V. <info at laixer dot com> 9 : * 10 : * Permission is hereby granted, free of charge, to any person obtaining a 11 : * copy of this software and associated documentation files (the "Software"), 12 : * to deal in the Software without restriction, including without limitation 13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense, 14 : * and/or sell copies of the Software, and to permit persons to whom the 15 : * Software is furnished to do so, subject to the following conditions: 16 : * 17 : * The above copyright notice and this permission notice shall be included 18 : * in all copies or substantial portions of the Software. 19 : * 20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 : * DEALINGS IN THE SOFTWARE. 27 : ****************************************************************************/ 28 : 29 : #include "ogr_lvbag.h" 30 : #include "ogrsf_frmts.h" 31 : 32 : /************************************************************************/ 33 : /* Identify() */ 34 : /************************************************************************/ 35 : 36 46930 : static int OGRLVBAGDriverIdentify(GDALOpenInfo *poOpenInfo) 37 : { 38 46930 : if (!poOpenInfo->bStatOK) 39 40527 : return FALSE; 40 6403 : if (poOpenInfo->bIsDirectory) 41 1232 : return -1; // Check later 42 5171 : if (poOpenInfo->fpL == nullptr) 43 82 : return FALSE; 44 : 45 5089 : auto pszPtr = reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 46 5089 : if (poOpenInfo->nHeaderBytes == 0 || pszPtr[0] != '<') 47 4033 : return FALSE; 48 : 49 : // Can't handle mutations just yet 50 1056 : if (strstr(pszPtr, 51 : "http://www.kadaster.nl/schemas/mutatielevering-generiek/1.0") != 52 : nullptr) 53 0 : return FALSE; 54 : 55 1056 : if (strstr(pszPtr, 56 : "http://www.kadaster.nl/schemas/standlevering-generiek/1.0") == 57 : nullptr) 58 1004 : return FALSE; 59 : 60 : // Pin the driver to XSD version 'v20200601' 61 52 : if (strstr(pszPtr, "http://www.kadaster.nl/schemas/lvbag/" 62 : "extract-deelbestand-lvc/v20200601") == nullptr) 63 1 : return FALSE; 64 : 65 51 : return TRUE; 66 : } 67 : 68 : /************************************************************************/ 69 : /* Open() */ 70 : /************************************************************************/ 71 : 72 635 : GDALDataset *OGRLVBAGDriverOpen(GDALOpenInfo *poOpenInfo) 73 : { 74 635 : if (!OGRLVBAGDriverIdentify(poOpenInfo) || poOpenInfo->eAccess == GA_Update) 75 87 : return nullptr; 76 : 77 548 : const char *pszFilename = poOpenInfo->pszFilename; 78 1096 : auto poDS = std::unique_ptr<OGRLVBAGDataSource>{new OGRLVBAGDataSource{}}; 79 548 : poDS->SetDescription(pszFilename); 80 : 81 548 : if (!poOpenInfo->bIsDirectory && poOpenInfo->fpL != nullptr) 82 : { 83 23 : if (!poDS->Open(pszFilename, poOpenInfo->papszOpenOptions)) 84 0 : poDS.reset(); 85 : } 86 525 : else if (poOpenInfo->bIsDirectory && poOpenInfo->fpL == nullptr) 87 : { 88 525 : int nProbedFileCount = 0; 89 525 : bool bFound = false; 90 525 : char **papszNames = VSIReadDir(pszFilename); 91 24146 : for (int i = 0; papszNames != nullptr && papszNames[i] != nullptr; ++i) 92 : { 93 23621 : if (!EQUAL(CPLGetExtension(papszNames[i]), "xml")) 94 23616 : continue; 95 : 96 : const CPLString oSubFilename = 97 17 : CPLFormFilename(pszFilename, papszNames[i], nullptr); 98 : 99 17 : if (EQUAL(papszNames[i], ".") || EQUAL(papszNames[i], "..")) 100 0 : continue; 101 : 102 : // Give up on /vsi filesystems if after 10 files we haven't found 103 : // a single BAG file 104 17 : if (nProbedFileCount == 10 && !bFound && 105 1 : STARTS_WITH(pszFilename, "/vsi")) 106 : { 107 0 : const bool bCheckAllFiles = CPLTestBool( 108 : CPLGetConfigOption("OGR_LVBAG_CHECK_ALL_FILES", "NO")); 109 0 : if (!bCheckAllFiles) 110 0 : break; 111 : } 112 : 113 17 : nProbedFileCount++; 114 17 : GDALOpenInfo oOpenInfo{oSubFilename, GA_ReadOnly}; 115 17 : if (OGRLVBAGDriverIdentify(&oOpenInfo) != TRUE) 116 12 : continue; 117 : 118 5 : if (poDS->Open(oSubFilename, poOpenInfo->papszOpenOptions)) 119 : { 120 5 : bFound = true; 121 : } 122 : } 123 : 124 525 : CSLDestroy(papszNames); 125 525 : if (!poDS->GetLayerCount()) 126 : { 127 523 : poDS.reset(); 128 523 : return nullptr; 129 2 : } 130 : } 131 : else 132 : { 133 0 : poDS.reset(); 134 0 : return nullptr; 135 : } 136 : 137 25 : return poDS.release(); 138 : } 139 : 140 : /************************************************************************/ 141 : /* RegisterOGRLVBAG() */ 142 : /************************************************************************/ 143 : 144 1522 : void RegisterOGRLVBAG() 145 : { 146 1522 : if (GDALGetDriverByName("LVBAG") != nullptr) 147 301 : return; 148 : 149 2442 : auto poDriver = std::make_unique<GDALDriver>(); 150 : 151 1221 : poDriver->SetDescription("LVBAG"); 152 1221 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 153 1221 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Kadaster LV BAG Extract 2.0"); 154 1221 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml"); 155 1221 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/lvbag.html"); 156 1221 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 157 1221 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 158 : 159 1221 : poDriver->SetMetadataItem( 160 : GDAL_DMD_OPENOPTIONLIST, 161 : "<OpenOptionList>" 162 : " <Option name='AUTOCORRECT_INVALID_DATA' type='boolean' " 163 : "description='whether driver should try to fix invalid data' " 164 : "default='NO'/>" 165 : " <Option name='LEGACY_ID' type='boolean' description='whether driver " 166 : "should use the BAG 1.0 identifiers' default='NO'/>" 167 1221 : "</OpenOptionList>"); 168 : 169 1221 : poDriver->pfnOpen = OGRLVBAGDriverOpen; 170 1221 : poDriver->pfnIdentify = OGRLVBAGDriverIdentify; 171 : 172 1221 : GetGDALDriverManager()->RegisterDriver(poDriver.release()); 173 : }