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 50597 : static int OGRLVBAGDriverIdentify(GDALOpenInfo *poOpenInfo) 21 : { 22 50597 : if (!poOpenInfo->bStatOK) 23 43585 : return FALSE; 24 7012 : if (poOpenInfo->bIsDirectory) 25 1331 : return -1; // Check later 26 5681 : if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes == 0) 27 151 : return FALSE; 28 : 29 5530 : auto pszPtr = reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 30 5530 : if (pszPtr[0] != '<') 31 4374 : return FALSE; 32 : 33 1156 : if (poOpenInfo->IsSingleAllowedDriver("LVBAG")) 34 2 : return TRUE; 35 : 36 : // Can't handle mutations just yet 37 1154 : if (strstr(pszPtr, 38 : "http://www.kadaster.nl/schemas/mutatielevering-generiek/1.0") != 39 : nullptr) 40 0 : return FALSE; 41 : 42 1154 : if (strstr(pszPtr, 43 : "http://www.kadaster.nl/schemas/standlevering-generiek/1.0") == 44 : nullptr) 45 1102 : 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 683 : GDALDataset *OGRLVBAGDriverOpen(GDALOpenInfo *poOpenInfo) 60 : { 61 683 : if (!OGRLVBAGDriverIdentify(poOpenInfo) || poOpenInfo->eAccess == GA_Update) 62 89 : return nullptr; 63 : 64 594 : const char *pszFilename = poOpenInfo->pszFilename; 65 1188 : auto poDS = std::unique_ptr<OGRLVBAGDataSource>{new OGRLVBAGDataSource{}}; 66 594 : poDS->SetDescription(pszFilename); 67 : 68 594 : if (!poOpenInfo->bIsDirectory && poOpenInfo->fpL != nullptr) 69 : { 70 24 : if (!poDS->Open(pszFilename, poOpenInfo->papszOpenOptions)) 71 0 : poDS.reset(); 72 : } 73 570 : else if (poOpenInfo->bIsDirectory && poOpenInfo->fpL == nullptr) 74 : { 75 570 : int nProbedFileCount = 0; 76 570 : bool bFound = false; 77 570 : char **papszNames = VSIReadDir(pszFilename); 78 25536 : for (int i = 0; papszNames != nullptr && papszNames[i] != nullptr; ++i) 79 : { 80 24966 : if (!EQUAL(CPLGetExtensionSafe(papszNames[i]).c_str(), "xml")) 81 24961 : continue; 82 : 83 : const CPLString oSubFilename = 84 17 : CPLFormFilenameSafe(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 570 : CSLDestroy(papszNames); 112 570 : if (!poDS->GetLayerCount()) 113 : { 114 568 : poDS.reset(); 115 568 : 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 1682 : void RegisterOGRLVBAG() 132 : { 133 1682 : if (GDALGetDriverByName("LVBAG") != nullptr) 134 301 : return; 135 : 136 2762 : auto poDriver = std::make_unique<GDALDriver>(); 137 : 138 1381 : poDriver->SetDescription("LVBAG"); 139 1381 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 140 1381 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Kadaster LV BAG Extract 2.0"); 141 1381 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml"); 142 1381 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/lvbag.html"); 143 1381 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 144 1381 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 145 : 146 1381 : 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 1381 : "</OpenOptionList>"); 155 : 156 1381 : poDriver->pfnOpen = OGRLVBAGDriverOpen; 157 1381 : poDriver->pfnIdentify = OGRLVBAGDriverIdentify; 158 : 159 1381 : GetGDALDriverManager()->RegisterDriver(poDriver.release()); 160 : }