1 /******************************************************************************
2  *
3  * Project:  OpenGIS Simple Features Reference Implementation
4  * Purpose:  OGR Driver for DGNv8
5  * Author:   Even Rouault <even.rouault at spatialys.com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.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_dgnv8.h"
30 #include "cpl_conv.h"
31 #include "ogrteigha.h"
32 
33 CPL_CVSID("$Id: ogrdgnv8driver.cpp 1761acd90777d5bcc49eddbc13c193098f0ed40b 2020-10-01 12:12:00 +0200 Even Rouault $")
34 
35 /************************************************************************/
36 /*                         OGRDGNV8DriverUnload()                       */
37 /************************************************************************/
38 
OGRDGNV8DriverUnload(GDALDriver *)39 static void OGRDGNV8DriverUnload( GDALDriver* )
40 {
41     CPLDebug("DGNv8", "Driver cleanup");
42     OGRTEIGHADeinitialize();
43 }
44 
45 /************************************************************************/
46 /*                         OGRDGNV8DriverIdentify()                     */
47 /************************************************************************/
48 
OGRDGNV8DriverIdentify(GDALOpenInfo * poOpenInfo)49 static int OGRDGNV8DriverIdentify( GDALOpenInfo* poOpenInfo )
50 
51 {
52     VSIStatBuf sStat;
53     if(  poOpenInfo->fpL != nullptr &&
54          poOpenInfo->nHeaderBytes >= 512 )
55     {
56         // Is it a DGN v7 cell library?
57         if( poOpenInfo->pabyHeader[0] == 0x08
58             && poOpenInfo->pabyHeader[1] == 0x05
59             && poOpenInfo->pabyHeader[2] == 0x17
60             && poOpenInfo->pabyHeader[3] == 0x00 )
61         {
62             return GDALGetDriverByName("DGN") == nullptr &&
63                    VSIStat(poOpenInfo->pszFilename, &sStat) == 0;
64         }
65 
66         // Is it a DGN v7 regular 2D or 3D file?
67         if( (poOpenInfo->pabyHeader[0] == 0x08 ||
68              poOpenInfo->pabyHeader[0] == 0xC8)
69             && poOpenInfo->pabyHeader[1] == 0x09
70             && poOpenInfo->pabyHeader[2] == 0xFE
71             && poOpenInfo->pabyHeader[3] == 0x02 )
72         {
73             return GDALGetDriverByName("DGN") == nullptr &&
74                    VSIStat(poOpenInfo->pszFilename, &sStat) == 0;
75         }
76     }
77 
78     return poOpenInfo->fpL != nullptr &&
79            poOpenInfo->nHeaderBytes >= 512 &&
80            EQUAL( CPLGetExtension(poOpenInfo->pszFilename), "DGN" ) &&
81            memcmp(poOpenInfo->pabyHeader,
82                   "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) == 0 &&
83            VSIStat(poOpenInfo->pszFilename, &sStat) == 0;
84 }
85 
86 /************************************************************************/
87 /*                                Open()                                */
88 /************************************************************************/
89 
OGRDGNV8DriverOpen(GDALOpenInfo * poOpenInfo)90 static GDALDataset *OGRDGNV8DriverOpen( GDALOpenInfo* poOpenInfo )
91 
92 {
93     if( !OGRDGNV8DriverIdentify(poOpenInfo))
94         return nullptr;
95 
96     if( !OGRTEIGHAInitialize() )
97         return nullptr;
98 
99     OGRDGNV8DataSource *poDS = new OGRDGNV8DataSource(OGRDGNV8GetServices());
100     if( !poDS->Open( poOpenInfo->pszFilename,
101                      poOpenInfo->eAccess == GA_Update) )
102     {
103         delete poDS;
104         return nullptr;
105     }
106 
107     return poDS;
108 }
109 
110 /************************************************************************/
111 /*                              Create()                                */
112 /************************************************************************/
113 
OGRDGNV8DriverCreate(const char * pszName,int,int,int,GDALDataType,char ** papszOptions)114 static GDALDataset *OGRDGNV8DriverCreate( const char * pszName,
115                                         int /* nBands */,
116                                         int /* nXSize */,
117                                         int /* nYSize */,
118                                         GDALDataType /* eDT */,
119                                         char **papszOptions )
120 {
121     if( !OGRTEIGHAInitialize() )
122         return nullptr;
123 
124     OGRDGNV8DataSource *poDS = new OGRDGNV8DataSource(OGRDGNV8GetServices());
125     if( !poDS->PreCreate( pszName, papszOptions ) )
126     {
127         delete poDS;
128         return nullptr;
129     }
130 
131     return poDS;
132 }
133 
134 /************************************************************************/
135 /*                         RegisterOGRDGNV8()                           */
136 /************************************************************************/
137 
RegisterOGRDGNV8()138 void RegisterOGRDGNV8()
139 
140 {
141     if( GDALGetDriverByName( "DGNV8" ) != nullptr )
142         return;
143 
144     GDALDriver  *poDriver = new GDALDriver();
145 
146     poDriver->SetDescription( "DGNV8" );
147     poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
148     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Microstation DGNv8" );
149     poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "dgn" );
150     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/dgnv8.html" );
151     poDriver->SetMetadataItem( GDAL_DCAP_FEATURE_STYLES, "YES" );
152 
153     poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
154 "<CreationOptionList>"
155 "  <Option name='SEED' type='string' "
156     "description='Filename of seed file to use'/>"
157 "  <Option name='COPY_SEED_FILE_COLOR_TABLE' type='boolean' "
158     "description='whether the color table should be copied from the "
159     "seed file.' default='NO'/>"
160 "  <Option name='COPY_SEED_FILE_MODEL' type='boolean' "
161     "description='whether the existing models (without their graphic "
162     "contents) should be copied from the seed file.' default='YES'/>"
163 "  <Option name='COPY_SEED_FILE_MODEL_CONTROL_ELEMENTS' type='boolean' "
164     "description='whether the existing control elements of models should be "
165     "copied from the seed file.' default='YES'/>"
166 "  <Option name='APPLICATION' type='string' "
167     "description='Set Application field in header'/>"
168 "  <Option name='TITLE' type='string' "
169     "description='Set Title field in header'/>"
170 "  <Option name='SUBJECT' type='string' "
171     "description='Set Subject field in header'/>"
172 "  <Option name='AUTHOR' type='string' "
173     "description='Set Author field in header'/>"
174 "  <Option name='KEYWORDS' type='string' "
175     "description='Set Keywords field in header'/>"
176 "  <Option name='TEMPLATE' type='string' "
177     "description='Set Template field in header'/>"
178 "  <Option name='COMMENTS' type='string' "
179     "description='Set Comments field in header'/>"
180 "  <Option name='LAST_SAVED_BY' type='string' "
181     "description='Set LastSavedBy field in header'/>"
182 "  <Option name='REVISION_NUMBER' type='string' "
183     "description='Set RevisionNumber field in header'/>"
184 "  <Option name='CATEGORY' type='string' "
185     "description='Set Category field in header'/>"
186 "  <Option name='MANAGER' type='string' "
187     "description='Set Manager field in header'/>"
188 "  <Option name='COMPANY' type='string' "
189     "description='Set Company field in header'/>"
190 "</CreationOptionList>");
191 
192     poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
193 "<LayerCreationOptionList>"
194 "  <Option name='DESCRIPTION' type='string' "
195     "description='Description of the layer/model'/>"
196 "  <Option name='DIM' type='int' "
197     "description='Dimension (2 or 3) of the layer/model'/>"
198 "</LayerCreationOptionList>" );
199 
200     poDriver->pfnOpen = OGRDGNV8DriverOpen;
201     poDriver->pfnIdentify = OGRDGNV8DriverIdentify;
202     poDriver->pfnCreate = OGRDGNV8DriverCreate;
203     poDriver->pfnUnloadDriver = OGRDGNV8DriverUnload;
204 
205     GetGDALDriverManager()->RegisterDriver( poDriver );
206 }
207