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 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #include "ogr_selafin.h"
13 : #include "cpl_conv.h"
14 : #include "cpl_string.h"
15 : #include "io_selafin.h"
16 :
17 : /************************************************************************/
18 : /* OGRSelafinDriverIdentify() */
19 : /************************************************************************/
20 :
21 66595 : static int OGRSelafinDriverIdentify(GDALOpenInfo *poOpenInfo)
22 : {
23 66595 : if (poOpenInfo->pabyHeader != nullptr)
24 : {
25 2447 : if (poOpenInfo->nHeaderBytes < 84 + 8)
26 238 : return FALSE;
27 2209 : if (poOpenInfo->pabyHeader[0] != 0 || poOpenInfo->pabyHeader[1] != 0 ||
28 113 : poOpenInfo->pabyHeader[2] != 0 || poOpenInfo->pabyHeader[3] != 0x50)
29 2203 : return FALSE;
30 :
31 6 : if (poOpenInfo->pabyHeader[84 + 0] != 0 ||
32 6 : poOpenInfo->pabyHeader[84 + 1] != 0 ||
33 6 : poOpenInfo->pabyHeader[84 + 2] != 0 ||
34 6 : poOpenInfo->pabyHeader[84 + 3] != 0x50 ||
35 6 : poOpenInfo->pabyHeader[84 + 4] != 0 ||
36 6 : poOpenInfo->pabyHeader[84 + 5] != 0 ||
37 6 : poOpenInfo->pabyHeader[84 + 6] != 0 ||
38 6 : poOpenInfo->pabyHeader[84 + 7] != 8)
39 0 : return FALSE;
40 :
41 6 : return TRUE;
42 : }
43 :
44 : // We can stat() the file but it is not a regular file or we did not
45 : // get access to its content
46 64148 : if (poOpenInfo->bStatOK)
47 536 : return FALSE;
48 :
49 63612 : return -1;
50 : }
51 :
52 : /************************************************************************/
53 : /* OGRSelafinDriverOpen() */
54 : /************************************************************************/
55 :
56 21540 : static GDALDataset *OGRSelafinDriverOpen(GDALOpenInfo *poOpenInfo)
57 : {
58 :
59 21540 : if (OGRSelafinDriverIdentify(poOpenInfo) == 0)
60 0 : return nullptr;
61 :
62 21540 : OGRSelafinDataSource *poDS = new OGRSelafinDataSource();
63 21540 : if (!poDS->Open(poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update,
64 : FALSE))
65 : {
66 21537 : delete poDS;
67 21537 : poDS = nullptr;
68 : }
69 21540 : return poDS;
70 : }
71 :
72 : /************************************************************************/
73 : /* OGRSelafinDriverCreate() */
74 : /************************************************************************/
75 :
76 : static GDALDataset *
77 19 : OGRSelafinDriverCreate(const char *pszName, CPL_UNUSED int nXSize,
78 : CPL_UNUSED int nYSize, CPL_UNUSED int nBands,
79 : CPL_UNUSED GDALDataType eDT, char **papszOptions)
80 : {
81 : // First, ensure there isn't any such file yet.
82 : VSIStatBufL sStatBuf;
83 19 : if (strcmp(pszName, "/dev/stdout") == 0)
84 0 : pszName = "/vsistdout/";
85 19 : if (VSIStatL(pszName, &sStatBuf) == 0)
86 : {
87 0 : CPLError(CE_Failure, CPLE_AppDefined,
88 : "It seems a file system object called '%s' already exists.",
89 : pszName);
90 0 : return nullptr;
91 : }
92 : // Parse options
93 19 : const char *pszTemp = CSLFetchNameValue(papszOptions, "TITLE");
94 : char pszTitle[81];
95 19 : int pnDate[6] = {-1, 0};
96 19 : if (pszTemp != nullptr)
97 0 : strncpy(pszTitle, pszTemp, 72);
98 : else
99 19 : memset(pszTitle, ' ', 72);
100 19 : pszTemp = CSLFetchNameValue(papszOptions, "DATE");
101 19 : if (pszTemp != nullptr)
102 : {
103 0 : const char *pszErrorMessage = "Wrong format for date parameter: must "
104 : "be \"%%Y-%%m-%%d_%%H:%%M:%%S\", ignored";
105 0 : const char *pszc = pszTemp;
106 0 : pnDate[0] = atoi(pszTemp);
107 0 : if (pnDate[0] <= 0)
108 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
109 : else
110 : {
111 0 : if (pnDate[0] < 100)
112 0 : pnDate[0] += 2000;
113 : }
114 0 : while (*pszc != 0 && *pszc != '-')
115 0 : ++pszc;
116 0 : pnDate[1] = atoi(pszc);
117 0 : if (pnDate[1] < 0 || pnDate[1] > 12)
118 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
119 0 : while (*pszc != 0 && *pszc != '_')
120 0 : ++pszc;
121 0 : pnDate[2] = atoi(pszc);
122 0 : if (pnDate[2] < 0 || pnDate[2] > 59)
123 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
124 0 : while (*pszc != 0 && *pszc != '_')
125 0 : ++pszc;
126 0 : pnDate[3] = atoi(pszc);
127 0 : if (pnDate[3] < 0 || pnDate[3] > 23)
128 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
129 0 : while (*pszc != 0 && *pszc != ':')
130 0 : ++pszc;
131 0 : pnDate[4] = atoi(pszc);
132 0 : if (pnDate[4] < 0 || pnDate[4] > 59)
133 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
134 0 : while (*pszc != 0 && *pszc != ':')
135 0 : ++pszc;
136 0 : pnDate[5] = atoi(pszc);
137 0 : if (pnDate[5] < 0 || pnDate[5] > 59)
138 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszErrorMessage);
139 : }
140 : // Create the skeleton of a Selafin file
141 19 : VSILFILE *fp = VSIFOpenL(pszName, "wb");
142 19 : if (fp == nullptr)
143 : {
144 1 : CPLError(CE_Failure, CPLE_AppDefined,
145 : "Unable to open %s with write access.", pszName);
146 1 : return nullptr;
147 : }
148 18 : strncpy(pszTitle + 72, "SERAPHIN", 9);
149 18 : bool bError = false;
150 18 : if (Selafin::write_string(fp, pszTitle, 80) == 0)
151 0 : bError = true;
152 18 : int pnTemp[10] = {0};
153 18 : if (Selafin::write_intarray(fp, pnTemp, 2) == 0)
154 0 : bError = true;
155 18 : if (pnDate[0] >= 0)
156 0 : pnTemp[9] = 1;
157 18 : if (Selafin::write_intarray(fp, pnTemp, 10) == 0)
158 0 : bError = true;
159 18 : if (pnDate[0] >= 0)
160 : {
161 0 : if (Selafin::write_intarray(fp, pnTemp, 6) == 0)
162 0 : bError = true;
163 : }
164 18 : pnTemp[3] = 1;
165 18 : if (Selafin::write_intarray(fp, pnTemp, 4) == 0)
166 0 : bError = true;
167 18 : if (Selafin::write_intarray(fp, pnTemp, 0) == 0)
168 0 : bError = true;
169 18 : if (Selafin::write_intarray(fp, pnTemp, 0) == 0)
170 0 : bError = true;
171 18 : if (Selafin::write_floatarray(fp, nullptr, 0) == 0)
172 0 : bError = true;
173 18 : if (Selafin::write_floatarray(fp, nullptr, 0) == 0)
174 0 : bError = true;
175 18 : VSIFCloseL(fp);
176 18 : if (bError)
177 : {
178 0 : CPLError(CE_Failure, CPLE_AppDefined, "Error writing to file %s.",
179 : pszName);
180 0 : return nullptr;
181 : }
182 : // Force it to open as a datasource
183 18 : OGRSelafinDataSource *poDS = new OGRSelafinDataSource();
184 18 : if (!poDS->Open(pszName, TRUE, TRUE))
185 : {
186 0 : delete poDS;
187 0 : return nullptr;
188 : }
189 18 : return poDS;
190 : }
191 :
192 : /************************************************************************/
193 : /* OGRSelafinDriverDelete() */
194 : /************************************************************************/
195 16 : static CPLErr OGRSelafinDriverDelete(const char *pszFilename)
196 : {
197 16 : if (CPLUnlinkTree(pszFilename) == 0)
198 16 : return CE_None;
199 : else
200 0 : return CE_Failure;
201 : }
202 :
203 : /************************************************************************/
204 : /* RegisterOGRSelafin() */
205 : /************************************************************************/
206 :
207 1595 : void RegisterOGRSelafin()
208 : {
209 :
210 1595 : if (GDALGetDriverByName("Selafin") != nullptr)
211 302 : return;
212 :
213 1293 : GDALDriver *poDriver = new GDALDriver();
214 :
215 1293 : poDriver->SetDescription("Selafin");
216 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
217 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
218 1293 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES");
219 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
220 1293 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
221 1293 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
222 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
223 :
224 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Selafin");
225 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
226 1293 : "drivers/vector/selafin.html");
227 :
228 1293 : poDriver->SetMetadataItem(
229 : GDAL_DMD_CREATIONOPTIONLIST,
230 : "<CreationOptionList>"
231 : " <Option name='TITLE' type='string' description='Title of the "
232 : "datasource, stored in the Selafin file. The title must not hold more "
233 : "than 72 characters.'/>"
234 : " <Option name='DATE' type='string' description='Starting date of the "
235 : "simulation. Each layer in a Selafin file is characterized by a date, "
236 : "counted in seconds since a reference date. This option allows "
237 : "providing the reference date. The format of this field must be "
238 : "YYYY-MM-DD_hh:mm:ss'/>"
239 1293 : "</CreationOptionList>");
240 1293 : poDriver->SetMetadataItem(
241 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
242 : "<LayerCreationOptionList>"
243 : " <Option name='DATE' type='float' description='Date of the time "
244 : "step, in seconds, relative to the starting date of the simulation.'/>"
245 1293 : "</LayerCreationOptionList>");
246 :
247 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
248 :
249 1293 : poDriver->pfnOpen = OGRSelafinDriverOpen;
250 1293 : poDriver->pfnIdentify = OGRSelafinDriverIdentify;
251 1293 : poDriver->pfnCreate = OGRSelafinDriverCreate;
252 1293 : poDriver->pfnDelete = OGRSelafinDriverDelete;
253 :
254 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
255 : }
|