Line data Source code
1 : /******************************************************************************
2 : * Project: Selafin importer
3 : * Purpose: Implementation of OGR driver for Selafin files.
4 : * Author: François Hissel, francois.hissel@gmail.com
5 : *
6 : ******************************************************************************
7 : * Copyright (c) 2014, François Hissel <francois.hissel@gmail.com>
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "ogr_selafin.h"
29 : #include "cpl_conv.h"
30 : #include "cpl_string.h"
31 : #include "io_selafin.h"
32 :
33 : /************************************************************************/
34 : /* OGRSelafinDriverIdentify() */
35 : /************************************************************************/
36 :
37 62069 : static int OGRSelafinDriverIdentify(GDALOpenInfo *poOpenInfo)
38 : {
39 62069 : if (poOpenInfo->pabyHeader != nullptr)
40 : {
41 2116 : if (poOpenInfo->nHeaderBytes < 84 + 8)
42 194 : return FALSE;
43 1922 : if (poOpenInfo->pabyHeader[0] != 0 || poOpenInfo->pabyHeader[1] != 0 ||
44 113 : poOpenInfo->pabyHeader[2] != 0 || poOpenInfo->pabyHeader[3] != 0x50)
45 1916 : return FALSE;
46 :
47 6 : if (poOpenInfo->pabyHeader[84 + 0] != 0 ||
48 6 : poOpenInfo->pabyHeader[84 + 1] != 0 ||
49 6 : poOpenInfo->pabyHeader[84 + 2] != 0 ||
50 6 : poOpenInfo->pabyHeader[84 + 3] != 0x50 ||
51 6 : poOpenInfo->pabyHeader[84 + 4] != 0 ||
52 6 : poOpenInfo->pabyHeader[84 + 5] != 0 ||
53 6 : poOpenInfo->pabyHeader[84 + 6] != 0 ||
54 6 : poOpenInfo->pabyHeader[84 + 7] != 8)
55 0 : return FALSE;
56 :
57 6 : return TRUE;
58 : }
59 :
60 : // We can stat() the file but it is not a regular file or we did not
61 : // get access to its content
62 59953 : if (poOpenInfo->bStatOK)
63 492 : return FALSE;
64 :
65 59461 : return -1;
66 : }
67 :
68 : /************************************************************************/
69 : /* OGRSelafinDriverOpen() */
70 : /************************************************************************/
71 :
72 20043 : static GDALDataset *OGRSelafinDriverOpen(GDALOpenInfo *poOpenInfo)
73 : {
74 :
75 20043 : if (OGRSelafinDriverIdentify(poOpenInfo) == 0)
76 0 : return nullptr;
77 :
78 20043 : OGRSelafinDataSource *poDS = new OGRSelafinDataSource();
79 20042 : if (!poDS->Open(poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update,
80 : FALSE))
81 : {
82 20040 : delete poDS;
83 20040 : poDS = nullptr;
84 : }
85 20043 : return poDS;
86 : }
87 :
88 : /************************************************************************/
89 : /* OGRSelafinDriverCreate() */
90 : /************************************************************************/
91 :
92 : static GDALDataset *
93 19 : OGRSelafinDriverCreate(const char *pszName, CPL_UNUSED int nXSize,
94 : CPL_UNUSED int nYSize, CPL_UNUSED int nBands,
95 : CPL_UNUSED GDALDataType eDT, char **papszOptions)
96 : {
97 : // First, ensure there isn't any such file yet.
98 : VSIStatBufL sStatBuf;
99 19 : if (strcmp(pszName, "/dev/stdout") == 0)
100 0 : pszName = "/vsistdout/";
101 19 : if (VSIStatL(pszName, &sStatBuf) == 0)
102 : {
103 0 : CPLError(CE_Failure, CPLE_AppDefined,
104 : "It seems a file system object called '%s' already exists.",
105 : pszName);
106 0 : return nullptr;
107 : }
108 : // Parse options
109 19 : const char *pszTemp = CSLFetchNameValue(papszOptions, "TITLE");
110 : char pszTitle[81];
111 19 : int pnDate[6] = {-1, 0};
112 19 : if (pszTemp != nullptr)
113 0 : strncpy(pszTitle, pszTemp, 72);
114 : else
115 19 : memset(pszTitle, ' ', 72);
116 19 : pszTemp = CSLFetchNameValue(papszOptions, "DATE");
117 19 : if (pszTemp != nullptr)
118 : {
119 0 : const char *pszErrorMessage = "Wrong format for date parameter: must "
120 : "be \"%%Y-%%m-%%d_%%H:%%M:%%S\", ignored";
121 0 : const char *pszc = pszTemp;
122 0 : pnDate[0] = atoi(pszTemp);
123 0 : if (pnDate[0] <= 0)
124 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
125 : else
126 : {
127 0 : if (pnDate[0] < 100)
128 0 : pnDate[0] += 2000;
129 : }
130 0 : while (*pszc != 0 && *pszc != '-')
131 0 : ++pszc;
132 0 : pnDate[1] = atoi(pszc);
133 0 : if (pnDate[1] < 0 || pnDate[1] > 12)
134 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
135 0 : while (*pszc != 0 && *pszc != '_')
136 0 : ++pszc;
137 0 : pnDate[2] = atoi(pszc);
138 0 : if (pnDate[2] < 0 || pnDate[2] > 59)
139 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
140 0 : while (*pszc != 0 && *pszc != '_')
141 0 : ++pszc;
142 0 : pnDate[3] = atoi(pszc);
143 0 : if (pnDate[3] < 0 || pnDate[3] > 23)
144 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
145 0 : while (*pszc != 0 && *pszc != ':')
146 0 : ++pszc;
147 0 : pnDate[4] = atoi(pszc);
148 0 : if (pnDate[4] < 0 || pnDate[4] > 59)
149 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
150 0 : while (*pszc != 0 && *pszc != ':')
151 0 : ++pszc;
152 0 : pnDate[5] = atoi(pszc);
153 0 : if (pnDate[5] < 0 || pnDate[5] > 59)
154 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
155 : }
156 : // Create the skeleton of a Selafin file
157 19 : VSILFILE *fp = VSIFOpenL(pszName, "wb");
158 19 : if (fp == nullptr)
159 : {
160 1 : CPLError(CE_Failure, CPLE_AppDefined,
161 : "Unable to open %s with write access.", pszName);
162 1 : return nullptr;
163 : }
164 18 : strncpy(pszTitle + 72, "SERAPHIN", 9);
165 18 : bool bError = false;
166 18 : if (Selafin::write_string(fp, pszTitle, 80) == 0)
167 0 : bError = true;
168 18 : int pnTemp[10] = {0};
169 18 : if (Selafin::write_intarray(fp, pnTemp, 2) == 0)
170 0 : bError = true;
171 18 : if (pnDate[0] >= 0)
172 0 : pnTemp[9] = 1;
173 18 : if (Selafin::write_intarray(fp, pnTemp, 10) == 0)
174 0 : bError = true;
175 18 : if (pnDate[0] >= 0)
176 : {
177 0 : if (Selafin::write_intarray(fp, pnTemp, 6) == 0)
178 0 : bError = true;
179 : }
180 18 : pnTemp[3] = 1;
181 18 : if (Selafin::write_intarray(fp, pnTemp, 4) == 0)
182 0 : bError = true;
183 18 : if (Selafin::write_intarray(fp, pnTemp, 0) == 0)
184 0 : bError = true;
185 18 : if (Selafin::write_intarray(fp, pnTemp, 0) == 0)
186 0 : bError = true;
187 18 : if (Selafin::write_floatarray(fp, nullptr, 0) == 0)
188 0 : bError = true;
189 18 : if (Selafin::write_floatarray(fp, nullptr, 0) == 0)
190 0 : bError = true;
191 18 : VSIFCloseL(fp);
192 18 : if (bError)
193 : {
194 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error writing to file %s.",
195 : pszName);
196 0 : return nullptr;
197 : }
198 : // Force it to open as a datasource
199 18 : OGRSelafinDataSource *poDS = new OGRSelafinDataSource();
200 18 : if (!poDS->Open(pszName, TRUE, TRUE))
201 : {
202 0 : delete poDS;
203 0 : return nullptr;
204 : }
205 18 : return poDS;
206 : }
207 :
208 : /************************************************************************/
209 : /* OGRSelafinDriverDelete() */
210 : /************************************************************************/
211 16 : static CPLErr OGRSelafinDriverDelete(const char *pszFilename)
212 : {
213 16 : if (CPLUnlinkTree(pszFilename) == 0)
214 16 : return CE_None;
215 : else
216 0 : return CE_Failure;
217 : }
218 :
219 : /************************************************************************/
220 : /* RegisterOGRSelafin() */
221 : /************************************************************************/
222 :
223 1512 : void RegisterOGRSelafin()
224 : {
225 :
226 1512 : if (GDALGetDriverByName("Selafin") != nullptr)
227 295 : return;
228 :
229 1217 : GDALDriver *poDriver = new GDALDriver();
230 :
231 1217 : poDriver->SetDescription("Selafin");
232 1217 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
233 1217 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
234 1217 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES");
235 1217 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
236 1217 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
237 1217 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
238 1217 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
239 :
240 1217 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Selafin");
241 1217 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
242 1217 : "drivers/vector/selafin.html");
243 :
244 1217 : poDriver->SetMetadataItem(
245 : GDAL_DMD_CREATIONOPTIONLIST,
246 : "<CreationOptionList>"
247 : " <Option name='TITLE' type='string' description='Title of the "
248 : "datasource, stored in the Selafin file. The title must not hold more "
249 : "than 72 characters.'/>"
250 : " <Option name='DATE' type='string' description='Starting date of the "
251 : "simulation. Each layer in a Selafin file is characterized by a date, "
252 : "counted in seconds since a reference date. This option allows "
253 : "providing the reference date. The format of this field must be "
254 : "YYYY-MM-DD_hh:mm:ss'/>"
255 1217 : "</CreationOptionList>");
256 1217 : poDriver->SetMetadataItem(
257 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
258 : "<LayerCreationOptionList>"
259 : " <Option name='DATE' type='float' description='Date of the time "
260 : "step, in seconds, relative to the starting date of the simulation.'/>"
261 1217 : "</LayerCreationOptionList>");
262 :
263 1217 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
264 :
265 1217 : poDriver->pfnOpen = OGRSelafinDriverOpen;
266 1217 : poDriver->pfnIdentify = OGRSelafinDriverIdentify;
267 1217 : poDriver->pfnCreate = OGRSelafinDriverCreate;
268 1217 : poDriver->pfnDelete = OGRSelafinDriverDelete;
269 :
270 1217 : GetGDALDriverManager()->RegisterDriver(poDriver);
271 : }
|