Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: mitab_ogr_driver.cpp
4 : * Project: MapInfo Mid/Mif, Tab ogr support
5 : * Language: C++
6 : * Purpose: Implementation of the MIDDATAFile class used to handle
7 : * reading/writing of the MID/MIF files
8 : * Author: Stephane Villeneuve, stephane.v@videotron.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999, 2000, Stephane Villeneuve
12 : * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : **********************************************************************/
32 :
33 : #include "mitab_ogr_driver.h"
34 :
35 : /************************************************************************/
36 : /* OGRTABDriverIdentify() */
37 : /************************************************************************/
38 :
39 51064 : static int OGRTABDriverIdentify(GDALOpenInfo *poOpenInfo)
40 :
41 : {
42 : // Files not ending with .tab, .mif or .mid are not handled by this driver.
43 51064 : if (!poOpenInfo->bStatOK)
44 40512 : return FALSE;
45 10552 : if (poOpenInfo->bIsDirectory)
46 1290 : return -1; // Unsure.
47 9262 : if (poOpenInfo->fpL == nullptr)
48 82 : return FALSE;
49 16636 : if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MIF") ||
50 7456 : EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MID"))
51 : {
52 1724 : return TRUE;
53 : }
54 7456 : if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "TAB"))
55 : {
56 223530 : for (int i = 0; i < poOpenInfo->nHeaderBytes; i++)
57 : {
58 223530 : const char *pszLine =
59 223530 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader) + i;
60 223530 : if (STARTS_WITH_CI(pszLine, "Fields"))
61 2459 : return TRUE;
62 221071 : else if (STARTS_WITH_CI(pszLine, "create view"))
63 4 : return TRUE;
64 221067 : else if (STARTS_WITH_CI(pszLine, "\"\\IsSeamless\" = \"TRUE\""))
65 0 : return TRUE;
66 : }
67 : }
68 : #ifdef DEBUG
69 : // For AFL, so that .cur_input is detected as the archive filename.
70 9986 : if (!STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
71 4993 : EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
72 : {
73 4 : return -1;
74 : }
75 : #endif
76 4989 : return FALSE;
77 : }
78 :
79 : /************************************************************************/
80 : /* OGRTABDriver::Open() */
81 : /************************************************************************/
82 :
83 2760 : static GDALDataset *OGRTABDriverOpen(GDALOpenInfo *poOpenInfo)
84 :
85 : {
86 2760 : if (OGRTABDriverIdentify(poOpenInfo) == FALSE)
87 : {
88 2 : return nullptr;
89 : }
90 :
91 4652 : if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MIF") ||
92 1894 : EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MID"))
93 : {
94 864 : if (poOpenInfo->eAccess == GA_Update)
95 0 : return nullptr;
96 : }
97 :
98 : #ifdef DEBUG
99 : // For AFL, so that .cur_input is detected as the archive filename.
100 7617 : if (poOpenInfo->fpL != nullptr &&
101 4859 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
102 2101 : EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
103 : {
104 : GDALOpenInfo oOpenInfo(
105 4 : (CPLString("/vsitar/") + poOpenInfo->pszFilename).c_str(),
106 6 : poOpenInfo->nOpenFlags);
107 2 : oOpenInfo.papszOpenOptions = poOpenInfo->papszOpenOptions;
108 2 : return OGRTABDriverOpen(&oOpenInfo);
109 : }
110 : #endif
111 :
112 2756 : OGRTABDataSource *poDS = new OGRTABDataSource();
113 2756 : if (!poDS->Open(poOpenInfo, TRUE))
114 : {
115 686 : delete poDS;
116 686 : return nullptr;
117 : }
118 :
119 2070 : return poDS;
120 : }
121 :
122 : /************************************************************************/
123 : /* Create() */
124 : /************************************************************************/
125 :
126 : static GDALDataset *
127 184 : OGRTABDriverCreate(const char *pszName, CPL_UNUSED int nBands,
128 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
129 : CPL_UNUSED GDALDataType eDT, char **papszOptions)
130 : {
131 : // Try to create the data source.
132 184 : OGRTABDataSource *poDS = new OGRTABDataSource();
133 184 : if (!poDS->Create(pszName, papszOptions))
134 : {
135 2 : delete poDS;
136 2 : return nullptr;
137 : }
138 :
139 182 : return poDS;
140 : }
141 :
142 : /************************************************************************/
143 : /* Delete() */
144 : /************************************************************************/
145 :
146 47 : static CPLErr OGRTABDriverDelete(const char *pszDataSource)
147 :
148 : {
149 47 : GDALDataset *poDS = nullptr;
150 : {
151 : // Make sure that the file opened by GDALOpenInfo is closed
152 : // when the object goes out of scope
153 47 : GDALOpenInfo oOpenInfo(pszDataSource, GA_ReadOnly);
154 47 : poDS = OGRTABDriverOpen(&oOpenInfo);
155 : }
156 47 : if (poDS == nullptr)
157 16 : return CE_Failure;
158 31 : char **papszFileList = poDS->GetFileList();
159 31 : delete poDS;
160 :
161 31 : char **papszIter = papszFileList;
162 211 : while (papszIter && *papszIter)
163 : {
164 180 : VSIUnlink(*papszIter);
165 180 : papszIter++;
166 : }
167 31 : CSLDestroy(papszFileList);
168 :
169 : VSIStatBufL sStatBuf;
170 31 : if (VSIStatL(pszDataSource, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode))
171 : {
172 16 : VSIRmdir(pszDataSource);
173 : }
174 :
175 31 : return CE_None;
176 : }
177 :
178 : /************************************************************************/
179 : /* OGRTABDriverUnload() */
180 : /************************************************************************/
181 :
182 852 : static void OGRTABDriverUnload(CPL_UNUSED GDALDriver *poDriver)
183 : {
184 852 : MITABFreeCoordSysTable();
185 852 : }
186 :
187 : /************************************************************************/
188 : /* RegisterOGRTAB() */
189 : /************************************************************************/
190 :
191 1520 : void RegisterOGRTAB()
192 :
193 : {
194 1520 : if (GDALGetDriverByName("MapInfo File") != nullptr)
195 301 : return;
196 :
197 1219 : GDALDriver *poDriver = new GDALDriver();
198 :
199 1219 : poDriver->SetDescription("MapInfo File");
200 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
201 1219 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
202 1219 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
203 1219 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
204 1219 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
205 1219 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
206 :
207 1219 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "MapInfo File");
208 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "tab mif mid");
209 1219 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/mitab.html");
210 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
211 1219 : poDriver->SetMetadataItem(GDAL_DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN,
212 1219 : "YES");
213 1219 : poDriver->SetMetadataItem(
214 1219 : GDAL_DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR, "YES");
215 :
216 1219 : poDriver->SetMetadataItem(
217 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
218 : "<LayerCreationOptionList>"
219 : " <Option name='BOUNDS' type='string' "
220 : "description='Custom bounds. Expect format is "
221 : "xmin,ymin,xmax,ymax'/>"
222 : " <Option name='ENCODING' type='string' "
223 : "description='to override the encoding "
224 : "interpretation of the DAT/MID with any encoding "
225 : "supported by CPLRecode or to \"\" to avoid any "
226 : "recoding (Neutral charset)'/>"
227 : " <Option name='DESCRIPTION' type='string' "
228 : "description='Friendly name of table. Only for tab "
229 : "format.'/>" // See
230 : // https://support.pitneybowes.com/SearchArticles/VFP05_KnowledgeWithSidebarHowTo?id=kA180000000CtuHCAS&popup=false&lang=en_US
231 1219 : "</LayerCreationOptionList>");
232 :
233 1219 : poDriver->SetMetadataItem(
234 : GDAL_DMD_CREATIONOPTIONLIST,
235 : "<CreationOptionList>"
236 : " <Option name='FORMAT' type='string-select' description='type of "
237 : "MapInfo format'>"
238 : " <Value>MIF</Value>"
239 : " <Value>TAB</Value>"
240 : " </Option>"
241 : " <Option name='SPATIAL_INDEX_MODE' type='string-select' "
242 : "description='type of spatial index' default='QUICK'>"
243 : " <Value>QUICK</Value>"
244 : " <Value>OPTIMIZED</Value>"
245 : " </Option>"
246 : " <Option name='BLOCKSIZE' type='int' description='.map block size' "
247 : "min='512' max='32256' default='512'/>"
248 : " <Option name='ENCODING' type='string' description='to override the "
249 : "encoding interpretation of the DAT/MID with any encoding supported by "
250 : "CPLRecode or to \"\" to avoid any recoding (Neutral charset)'/>"
251 1219 : "</CreationOptionList>");
252 :
253 1219 : poDriver->SetMetadataItem(
254 : GDAL_DMD_CREATIONFIELDDATATYPES,
255 1219 : "Integer Integer64 Real String Date DateTime Time");
256 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
257 1219 : "WidthPrecision");
258 1219 : poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
259 1219 : "Name Type WidthPrecision");
260 1219 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES");
261 1219 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES");
262 1219 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_WRITE, "YES");
263 :
264 1219 : poDriver->pfnOpen = OGRTABDriverOpen;
265 1219 : poDriver->pfnIdentify = OGRTABDriverIdentify;
266 1219 : poDriver->pfnCreate = OGRTABDriverCreate;
267 1219 : poDriver->pfnDelete = OGRTABDriverDelete;
268 1219 : poDriver->pfnUnloadDriver = OGRTABDriverUnload;
269 :
270 1219 : GetGDALDriverManager()->RegisterDriver(poDriver);
271 : }
|