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 
OGRLVBAGDriverIdentify(GDALOpenInfo * poOpenInfo)36 static int OGRLVBAGDriverIdentify( GDALOpenInfo* poOpenInfo )
37 {
38     if( !poOpenInfo->bStatOK )
39         return FALSE;
40     if( poOpenInfo->bIsDirectory )
41         return -1;  // Check later
42     if( poOpenInfo->fpL == nullptr )
43         return FALSE;
44 
45     auto pszPtr = reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
46     if( poOpenInfo->nHeaderBytes == 0 || pszPtr[0] != '<' )
47         return FALSE;
48 
49     // Can't handle mutations just yet
50     if( strstr(pszPtr, "http://www.kadaster.nl/schemas/mutatielevering-generiek/1.0") != nullptr )
51         return FALSE;
52 
53     if( strstr(pszPtr, "http://www.kadaster.nl/schemas/standlevering-generiek/1.0") == nullptr )
54         return FALSE;
55 
56     // Pin the driver to XSD version 'v20200601'
57     if( strstr(pszPtr, "http://www.kadaster.nl/schemas/lvbag/extract-deelbestand-lvc/v20200601") == nullptr )
58         return FALSE;
59 
60     return TRUE;
61 }
62 
63 /************************************************************************/
64 /*                                Open()                                */
65 /************************************************************************/
66 
OGRLVBAGDriverOpen(GDALOpenInfo * poOpenInfo)67 GDALDataset *OGRLVBAGDriverOpen( GDALOpenInfo* poOpenInfo )
68 {
69     if( !OGRLVBAGDriverIdentify(poOpenInfo) ||
70         poOpenInfo->eAccess == GA_Update)
71         return nullptr;
72 
73     const char *pszFilename = poOpenInfo->pszFilename;
74     auto poDS = std::unique_ptr<OGRLVBAGDataSource>{
75         new OGRLVBAGDataSource{} };
76     poDS->SetDescription(pszFilename);
77 
78     if( !poOpenInfo->bIsDirectory && poOpenInfo->fpL != nullptr )
79     {
80         if( !poDS->Open( pszFilename, poOpenInfo->papszOpenOptions ) )
81             poDS.reset();
82     }
83     else if( poOpenInfo->bIsDirectory && poOpenInfo->fpL == nullptr )
84     {
85         char **papszNames = VSIReadDir(pszFilename);
86         for( int i = 0; papszNames != nullptr && papszNames[i] != nullptr; ++i )
87         {
88             const CPLString oSubFilename =
89                 CPLFormFilename(pszFilename, papszNames[i], nullptr);
90 
91             if( EQUAL(papszNames[i], ".") || EQUAL(papszNames[i], "..") )
92                 continue;
93 
94             GDALOpenInfo oOpenInfo{ oSubFilename, GA_ReadOnly };
95             if( OGRLVBAGDriverIdentify(&oOpenInfo) != TRUE )
96                 continue;
97 
98             if( !poDS->Open( oSubFilename, poOpenInfo->papszOpenOptions ) )
99                 continue;
100         }
101 
102         CSLDestroy(papszNames);
103         if( !poDS->GetLayerCount() )
104         {
105             poDS.reset();
106             return nullptr;
107         }
108     }
109     else
110     {
111         poDS.reset();
112         return nullptr;
113     }
114 
115     return poDS.release();
116 }
117 
118 /************************************************************************/
119 /*                         RegisterOGRLVBAG()                           */
120 /************************************************************************/
121 
RegisterOGRLVBAG()122 void RegisterOGRLVBAG()
123 {
124     if( GDALGetDriverByName( "LVBAG" ) != nullptr )
125         return;
126 
127     std::unique_ptr<GDALDriver> poDriver = std::unique_ptr<GDALDriver>{ new GDALDriver };
128 
129     poDriver->SetDescription( "LVBAG" );
130     poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
131     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Kadaster LV BAG Extract 2.0" );
132     poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xml" );
133     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/lvbag.html" );
134     poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
135 
136     poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
137 "<OpenOptionList>"
138 "  <Option name='AUTOCORRECT_INVALID_DATA' type='boolean' description='whether driver should try to fix invalid data' default='NO'/>"
139 "  <Option name='LEGACY_ID' type='boolean' description='whether driver should use the BAG 1.0 identifiers' default='NO'/>"
140 "</OpenOptionList>" );
141 
142     poDriver->pfnOpen = OGRLVBAGDriverOpen;
143     poDriver->pfnIdentify = OGRLVBAGDriverIdentify;
144 
145     GetGDALDriverManager()->RegisterDriver(poDriver.release());
146 }
147