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 : * SPDX-License-Identifier: MIT
15 : **********************************************************************/
16 :
17 : #include "mitab_ogr_driver.h"
18 :
19 : /************************************************************************/
20 : /* OGRTABDriverIdentify() */
21 : /************************************************************************/
22 :
23 63804 : static int OGRTABDriverIdentify(GDALOpenInfo *poOpenInfo)
24 :
25 : {
26 : // Files not ending with .tab, .mif or .mid are not handled by this driver.
27 63804 : if (!poOpenInfo->bStatOK)
28 51264 : return FALSE;
29 12540 : if (poOpenInfo->bIsDirectory)
30 1731 : return -1; // Unsure.
31 10809 : if (poOpenInfo->fpL == nullptr)
32 91 : return FALSE;
33 19690 : if (poOpenInfo->IsExtensionEqualToCI("MIF") ||
34 8972 : poOpenInfo->IsExtensionEqualToCI("MID"))
35 : {
36 1746 : return TRUE;
37 : }
38 8972 : if (poOpenInfo->IsExtensionEqualToCI("TAB"))
39 : {
40 225772 : for (int i = 0; i < poOpenInfo->nHeaderBytes; i++)
41 : {
42 225772 : const char *pszLine =
43 225772 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader) + i;
44 225772 : if (STARTS_WITH_CI(pszLine, "Fields"))
45 2484 : return TRUE;
46 223288 : else if (STARTS_WITH_CI(pszLine, "create view"))
47 4 : return TRUE;
48 223284 : else if (STARTS_WITH_CI(pszLine, "\"\\IsSeamless\" = \"TRUE\""))
49 0 : return TRUE;
50 : }
51 : }
52 : #ifdef DEBUG
53 : // For AFL, so that .cur_input is detected as the archive filename.
54 12968 : if (!STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
55 6484 : EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
56 : {
57 4 : return -1;
58 : }
59 : #endif
60 6480 : return FALSE;
61 : }
62 :
63 : /************************************************************************/
64 : /* OGRTABDriver::Open() */
65 : /************************************************************************/
66 :
67 2933 : static GDALDataset *OGRTABDriverOpen(GDALOpenInfo *poOpenInfo)
68 :
69 : {
70 2933 : if (OGRTABDriverIdentify(poOpenInfo) == FALSE)
71 : {
72 2 : return nullptr;
73 : }
74 :
75 4987 : if (poOpenInfo->IsExtensionEqualToCI("MIF") ||
76 2056 : poOpenInfo->IsExtensionEqualToCI("MID"))
77 : {
78 875 : if (poOpenInfo->eAccess == GA_Update)
79 0 : return nullptr;
80 : }
81 :
82 : #ifdef DEBUG
83 : // For AFL, so that .cur_input is detected as the archive filename.
84 7987 : if (poOpenInfo->fpL != nullptr &&
85 5056 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
86 2125 : EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
87 : {
88 : GDALOpenInfo oOpenInfo(
89 4 : (CPLString("/vsitar/") + poOpenInfo->pszFilename).c_str(),
90 6 : poOpenInfo->nOpenFlags);
91 2 : oOpenInfo.papszOpenOptions = poOpenInfo->papszOpenOptions;
92 2 : return OGRTABDriverOpen(&oOpenInfo);
93 : }
94 : #endif
95 :
96 2929 : OGRTABDataSource *poDS = new OGRTABDataSource();
97 2929 : if (!poDS->Open(poOpenInfo, TRUE))
98 : {
99 833 : delete poDS;
100 833 : return nullptr;
101 : }
102 :
103 2096 : return poDS;
104 : }
105 :
106 : /************************************************************************/
107 : /* Create() */
108 : /************************************************************************/
109 :
110 : static GDALDataset *
111 201 : OGRTABDriverCreate(const char *pszName, CPL_UNUSED int nBands,
112 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
113 : CPL_UNUSED GDALDataType eDT, CSLConstList papszOptions)
114 : {
115 : // Try to create the data source.
116 201 : OGRTABDataSource *poDS = new OGRTABDataSource();
117 201 : if (!poDS->Create(pszName, papszOptions))
118 : {
119 2 : delete poDS;
120 2 : return nullptr;
121 : }
122 :
123 199 : return poDS;
124 : }
125 :
126 : /************************************************************************/
127 : /* Delete() */
128 : /************************************************************************/
129 :
130 48 : static CPLErr OGRTABDriverDelete(const char *pszDataSource)
131 :
132 : {
133 48 : GDALDataset *poDS = nullptr;
134 : {
135 : // Make sure that the file opened by GDALOpenInfo is closed
136 : // when the object goes out of scope
137 48 : GDALOpenInfo oOpenInfo(pszDataSource, GA_ReadOnly);
138 48 : poDS = OGRTABDriverOpen(&oOpenInfo);
139 : }
140 48 : if (poDS == nullptr)
141 16 : return CE_Failure;
142 32 : char **papszFileList = poDS->GetFileList();
143 32 : delete poDS;
144 :
145 32 : char **papszIter = papszFileList;
146 216 : while (papszIter && *papszIter)
147 : {
148 184 : VSIUnlink(*papszIter);
149 184 : papszIter++;
150 : }
151 32 : CSLDestroy(papszFileList);
152 :
153 : VSIStatBufL sStatBuf;
154 32 : if (VSIStatL(pszDataSource, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode))
155 : {
156 16 : VSIRmdir(pszDataSource);
157 : }
158 :
159 32 : return CE_None;
160 : }
161 :
162 : /************************************************************************/
163 : /* OGRTABDriverUnload() */
164 : /************************************************************************/
165 :
166 1131 : static void OGRTABDriverUnload(CPL_UNUSED GDALDriver *poDriver)
167 : {
168 1131 : MITABFreeCoordSysTable();
169 1131 : }
170 :
171 : /************************************************************************/
172 : /* RegisterOGRTAB() */
173 : /************************************************************************/
174 :
175 2058 : void RegisterOGRTAB()
176 :
177 : {
178 2058 : if (GDALGetDriverByName("MapInfo File") != nullptr)
179 263 : return;
180 :
181 1795 : GDALDriver *poDriver = new GDALDriver();
182 :
183 1795 : poDriver->SetDescription("MapInfo File");
184 1795 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
185 1795 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
186 1795 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
187 1795 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
188 1795 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
189 1795 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
190 1795 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS_IN_DIRECTORY,
191 1795 : "YES");
192 :
193 1795 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "MapInfo File");
194 1795 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "tab mif mid");
195 1795 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/mitab.html");
196 1795 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
197 1795 : poDriver->SetMetadataItem(GDAL_DMD_NUMERIC_FIELD_WIDTH_INCLUDES_SIGN,
198 1795 : "YES");
199 1795 : poDriver->SetMetadataItem(
200 1795 : GDAL_DMD_NUMERIC_FIELD_WIDTH_INCLUDES_DECIMAL_SEPARATOR, "YES");
201 :
202 1795 : poDriver->SetMetadataItem(
203 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
204 : "<LayerCreationOptionList>"
205 : " <Option name='BOUNDS' type='string' "
206 : "description='Custom bounds. Expect format is "
207 : "xmin,ymin,xmax,ymax'/>"
208 : " <Option name='ENCODING' type='string' "
209 : "description='to override the encoding "
210 : "interpretation of the DAT/MID with any encoding "
211 : "supported by CPLRecode or to \"\" to avoid any "
212 : "recoding (Neutral charset)'/>"
213 : " <Option name='DESCRIPTION' type='string' "
214 : "description='Friendly name of table. Only for tab "
215 : "format.'/>" // See
216 : // https://support.pitneybowes.com/SearchArticles/VFP05_KnowledgeWithSidebarHowTo?id=kA180000000CtuHCAS&popup=false&lang=en_US
217 : " <Option name='STRICT_FIELDS_NAME_LAUNDERING' type='boolean' "
218 : "default='YES' description='Field name consisting of alphanumeric "
219 : "only, maximum length 31'/>"
220 1795 : "</LayerCreationOptionList>");
221 :
222 1795 : poDriver->SetMetadataItem(
223 : GDAL_DMD_CREATIONOPTIONLIST,
224 : "<CreationOptionList>"
225 : " <Option name='FORMAT' type='string-select' description='type of "
226 : "MapInfo format'>"
227 : " <Value>MIF</Value>"
228 : " <Value>TAB</Value>"
229 : " </Option>"
230 : " <Option name='SPATIAL_INDEX_MODE' type='string-select' "
231 : "description='type of spatial index' default='QUICK'>"
232 : " <Value>QUICK</Value>"
233 : " <Value>OPTIMIZED</Value>"
234 : " </Option>"
235 : " <Option name='BLOCKSIZE' type='int' description='.map block size' "
236 : "min='512' max='32256' default='512'/>"
237 : " <Option name='ENCODING' type='string' description='to override the "
238 : "encoding interpretation of the DAT/MID with any encoding supported by "
239 : "CPLRecode or to \"\" to avoid any recoding (Neutral charset)'/>"
240 : " <Option name='STRICT_FIELDS_NAME_LAUNDERING' type='boolean' "
241 : "default='YES' description='Field name consisting of alphanumeric "
242 : "only, maximum length 31'/>"
243 1795 : "</CreationOptionList>");
244 :
245 1795 : poDriver->SetMetadataItem(
246 : GDAL_DMD_CREATIONFIELDDATATYPES,
247 1795 : "Integer Integer64 Real String Date DateTime Time");
248 1795 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
249 1795 : poDriver->SetMetadataItem(GDAL_DMD_MAX_STRING_LENGTH, "254");
250 1795 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
251 1795 : "WidthPrecision");
252 1795 : poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
253 1795 : "Name Type WidthPrecision");
254 1795 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES");
255 1795 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES");
256 1795 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_WRITE, "YES");
257 :
258 1795 : poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
259 1795 : poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "Features");
260 :
261 1795 : poDriver->pfnOpen = OGRTABDriverOpen;
262 1795 : poDriver->pfnIdentify = OGRTABDriverIdentify;
263 1795 : poDriver->pfnCreate = OGRTABDriverCreate;
264 1795 : poDriver->pfnDelete = OGRTABDriverDelete;
265 1795 : poDriver->pfnUnloadDriver = OGRTABDriverUnload;
266 :
267 1795 : GetGDALDriverManager()->RegisterDriver(poDriver);
268 : }
|