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 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "ogr_lvbag.h" 14 : #include "ogrsf_frmts.h" 15 : 16 : /************************************************************************/ 17 : /* Identify() */ 18 : /************************************************************************/ 19 : 20 50012 : static int OGRLVBAGDriverIdentify(GDALOpenInfo *poOpenInfo) 21 : { 22 50012 : if (!poOpenInfo->bStatOK) 23 43112 : return FALSE; 24 6900 : if (poOpenInfo->bIsDirectory) 25 1325 : return -1; // Check later 26 5575 : if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes == 0) 27 150 : return FALSE; 28 : 29 5425 : auto pszPtr = reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 30 5425 : if (pszPtr[0] != '<') 31 4274 : return FALSE; 32 : 33 1151 : if (poOpenInfo->IsSingleAllowedDriver("LVBAG")) 34 2 : return TRUE; 35 : 36 : // Can't handle mutations just yet 37 1149 : if (strstr(pszPtr, 38 : "http://www.kadaster.nl/schemas/mutatielevering-generiek/1.0") != 39 : nullptr) 40 0 : return FALSE; 41 : 42 1149 : if (strstr(pszPtr, 43 : "http://www.kadaster.nl/schemas/standlevering-generiek/1.0") == 44 : nullptr) 45 1097 : return FALSE; 46 : 47 : // Pin the driver to XSD version 'v20200601' 48 52 : if (strstr(pszPtr, "http://www.kadaster.nl/schemas/lvbag/" 49 : "extract-deelbestand-lvc/v20200601") == nullptr) 50 1 : return FALSE; 51 : 52 51 : return TRUE; 53 : } 54 : 55 : /************************************************************************/ 56 : /* Open() */ 57 : /************************************************************************/ 58 : 59 680 : GDALDataset *OGRLVBAGDriverOpen(GDALOpenInfo *poOpenInfo) 60 : { 61 680 : if (!OGRLVBAGDriverIdentify(poOpenInfo) || poOpenInfo->eAccess == GA_Update) 62 89 : return nullptr; 63 : 64 591 : const char *pszFilename = poOpenInfo->pszFilename; 65 1182 : auto poDS = std::unique_ptr<OGRLVBAGDataSource>{new OGRLVBAGDataSource{}}; 66 591 : poDS->SetDescription(pszFilename); 67 : 68 591 : if (!poOpenInfo->bIsDirectory && poOpenInfo->fpL != nullptr) 69 : { 70 24 : if (!poDS->Open(pszFilename, poOpenInfo->papszOpenOptions)) 71 0 : poDS.reset(); 72 : } 73 567 : else if (poOpenInfo->bIsDirectory && poOpenInfo->fpL == nullptr) 74 : { 75 567 : int nProbedFileCount = 0; 76 567 : bool bFound = false; 77 567 : char **papszNames = VSIReadDir(pszFilename); 78 25352 : for (int i = 0; papszNames != nullptr && papszNames[i] != nullptr; ++i) 79 : { 80 24785 : if (!EQUAL(CPLGetExtension(papszNames[i]), "xml")) 81 24780 : continue; 82 : 83 : const CPLString oSubFilename = 84 17 : CPLFormFilename(pszFilename, papszNames[i], nullptr); 85 : 86 17 : if (EQUAL(papszNames[i], ".") || EQUAL(papszNames[i], "..")) 87 0 : continue; 88 : 89 : // Give up on /vsi filesystems if after 10 files we haven't found 90 : // a single BAG file 91 17 : if (nProbedFileCount == 10 && !bFound && 92 1 : STARTS_WITH(pszFilename, "/vsi")) 93 : { 94 0 : const bool bCheckAllFiles = CPLTestBool( 95 : CPLGetConfigOption("OGR_LVBAG_CHECK_ALL_FILES", "NO")); 96 0 : if (!bCheckAllFiles) 97 0 : break; 98 : } 99 : 100 17 : nProbedFileCount++; 101 17 : GDALOpenInfo oOpenInfo{oSubFilename, GA_ReadOnly}; 102 17 : if (OGRLVBAGDriverIdentify(&oOpenInfo) != TRUE) 103 12 : continue; 104 : 105 5 : if (poDS->Open(oSubFilename, poOpenInfo->papszOpenOptions)) 106 : { 107 5 : bFound = true; 108 : } 109 : } 110 : 111 567 : CSLDestroy(papszNames); 112 567 : if (!poDS->GetLayerCount()) 113 : { 114 565 : poDS.reset(); 115 565 : return nullptr; 116 2 : } 117 : } 118 : else 119 : { 120 0 : poDS.reset(); 121 0 : return nullptr; 122 : } 123 : 124 26 : return poDS.release(); 125 : } 126 : 127 : /************************************************************************/ 128 : /* RegisterOGRLVBAG() */ 129 : /************************************************************************/ 130 : 131 1595 : void RegisterOGRLVBAG() 132 : { 133 1595 : if (GDALGetDriverByName("LVBAG") != nullptr) 134 302 : return; 135 : 136 2586 : auto poDriver = std::make_unique<GDALDriver>(); 137 : 138 1293 : poDriver->SetDescription("LVBAG"); 139 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 140 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Kadaster LV BAG Extract 2.0"); 141 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml"); 142 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/lvbag.html"); 143 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 144 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 145 : 146 1293 : poDriver->SetMetadataItem( 147 : GDAL_DMD_OPENOPTIONLIST, 148 : "<OpenOptionList>" 149 : " <Option name='AUTOCORRECT_INVALID_DATA' type='boolean' " 150 : "description='whether driver should try to fix invalid data' " 151 : "default='NO'/>" 152 : " <Option name='LEGACY_ID' type='boolean' description='whether driver " 153 : "should use the BAG 1.0 identifiers' default='NO'/>" 154 1293 : "</OpenOptionList>"); 155 : 156 1293 : poDriver->pfnOpen = OGRLVBAGDriverOpen; 157 1293 : poDriver->pfnIdentify = OGRLVBAGDriverIdentify; 158 : 159 1293 : GetGDALDriverManager()->RegisterDriver(poDriver.release()); 160 : }