1 : /******************************************************************************
2 : * $Id: ogrpdsdatasource.cpp 19988 2010-07-07 19:02:36Z rouault $
3 : *
4 : * Project: PDS Translator
5 : * Purpose: Implements OGRPDSDataSource class
6 : * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash paris dot org>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_pds.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrpdsdatasource.cpp 19988 2010-07-07 19:02:36Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRPDSDataSource() */
38 : /************************************************************************/
39 :
40 10 : OGRPDSDataSource::OGRPDSDataSource()
41 :
42 : {
43 10 : papoLayers = NULL;
44 10 : nLayers = 0;
45 :
46 10 : pszName = NULL;
47 10 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRPDSDataSource() */
51 : /************************************************************************/
52 :
53 10 : OGRPDSDataSource::~OGRPDSDataSource()
54 :
55 : {
56 11 : for( int i = 0; i < nLayers; i++ )
57 1 : delete papoLayers[i];
58 10 : CPLFree( papoLayers );
59 :
60 10 : CPLFree( pszName );
61 10 : }
62 :
63 : /************************************************************************/
64 : /* TestCapability() */
65 : /************************************************************************/
66 :
67 0 : int OGRPDSDataSource::TestCapability( const char * pszCap )
68 :
69 : {
70 0 : return FALSE;
71 : }
72 :
73 : /************************************************************************/
74 : /* GetLayer() */
75 : /************************************************************************/
76 :
77 1 : OGRLayer *OGRPDSDataSource::GetLayer( int iLayer )
78 :
79 : {
80 1 : if( iLayer < 0 || iLayer >= nLayers )
81 0 : return NULL;
82 : else
83 1 : return papoLayers[iLayer];
84 : }
85 :
86 :
87 : /************************************************************************/
88 : /* GetKeywordSub() */
89 : /************************************************************************/
90 :
91 : const char * OGRPDSDataSource::GetKeywordSub( const char *pszPath,
92 : int iSubscript,
93 2 : const char *pszDefault )
94 :
95 : {
96 2 : const char *pszResult = oKeywords.GetKeyword( pszPath, NULL );
97 :
98 2 : if( pszResult == NULL )
99 0 : return pszDefault;
100 :
101 2 : if( pszResult[0] != '(' )
102 0 : return pszDefault;
103 :
104 : char **papszTokens = CSLTokenizeString2( pszResult, "(,)",
105 2 : CSLT_HONOURSTRINGS );
106 :
107 2 : if( iSubscript <= CSLCount(papszTokens) )
108 : {
109 2 : osTempResult = papszTokens[iSubscript-1];
110 2 : CSLDestroy( papszTokens );
111 2 : return osTempResult.c_str();
112 : }
113 : else
114 : {
115 0 : CSLDestroy( papszTokens );
116 0 : return pszDefault;
117 : }
118 : }
119 :
120 : /************************************************************************/
121 : /* CleanString() */
122 : /* */
123 : /* Removes single or double quotes, and converts spaces to underscores. */
124 : /* The change is made in-place to CPLString. */
125 : /************************************************************************/
126 :
127 55 : void OGRPDSDataSource::CleanString( CPLString &osInput )
128 :
129 : {
130 55 : if( ( osInput.size() < 2 ) ||
131 : ((osInput.at(0) != '"' || osInput.at(osInput.size()-1) != '"' ) &&
132 : ( osInput.at(0) != '\'' || osInput.at(osInput.size()-1) != '\'')) )
133 29 : return;
134 :
135 26 : char *pszWrk = CPLStrdup(osInput.c_str() + 1);
136 : int i;
137 :
138 26 : pszWrk[strlen(pszWrk)-1] = '\0';
139 :
140 410 : for( i = 0; pszWrk[i] != '\0'; i++ )
141 : {
142 384 : if( pszWrk[i] == ' ' )
143 0 : pszWrk[i] = '_';
144 : }
145 :
146 26 : osInput = pszWrk;
147 26 : CPLFree( pszWrk );
148 : }
149 :
150 : /************************************************************************/
151 : /* LoadTable() */
152 : /************************************************************************/
153 :
154 4 : static CPLString MakeAttr(CPLString os1, CPLString os2)
155 : {
156 4 : return os1 + "." + os2;
157 : }
158 :
159 : int OGRPDSDataSource::LoadTable(const char* pszFilename,
160 : int nRecordSize,
161 1 : CPLString osTableID )
162 : {
163 :
164 1 : CPLString osTableFilename;
165 : int nStartBytes;
166 :
167 1 : CPLString osTableLink = "^";
168 1 : osTableLink += osTableID;
169 :
170 1 : CPLString osTable = oKeywords.GetKeyword( osTableLink, "" );
171 1 : if( osTable[0] == '(' )
172 : {
173 1 : osTableFilename = GetKeywordSub(osTableLink, 1, "");
174 1 : CPLString osStartRecord = GetKeywordSub(osTableLink, 2, "");
175 1 : nStartBytes = (atoi(osStartRecord.c_str()) - 1) * nRecordSize;
176 1 : if (osTableFilename.size() == 0 || osStartRecord.size() == 0 ||
177 : nStartBytes < 0)
178 : {
179 : CPLError(CE_Failure, CPLE_NotSupported,
180 0 : "Cannot parse %s line", osTableLink.c_str());
181 0 : return FALSE;
182 : }
183 1 : CPLString osTPath = CPLGetPath(pszFilename);
184 1 : CleanString( osTableFilename );
185 1 : osTableFilename = CPLFormCIFilename( osTPath, osTableFilename, NULL );
186 : }
187 : else
188 : {
189 0 : osTableFilename = oKeywords.GetKeyword( osTableLink, "" );
190 0 : if (osTableFilename.size() != 0 && osTableFilename[0] >= '0' &&
191 : osTableFilename[0] <= '9')
192 : {
193 0 : nStartBytes = atoi(osTableFilename.c_str()) - 1;
194 0 : if (strstr(osTableFilename.c_str(), "<BYTES>") == NULL)
195 0 : nStartBytes *= nRecordSize;
196 0 : osTableFilename = pszFilename;
197 : }
198 : else
199 : {
200 0 : CPLString osTPath = CPLGetPath(pszFilename);
201 0 : CleanString( osTableFilename );
202 0 : osTableFilename = CPLFormCIFilename( osTPath, osTableFilename, NULL );
203 0 : nStartBytes = 0;
204 : }
205 : }
206 :
207 1 : CPLString osTableName = oKeywords.GetKeyword( MakeAttr(osTableID, "NAME"), "" );
208 1 : if (osTableName.size() == 0)
209 : {
210 0 : if (GetLayerByName(osTableID.c_str()) == NULL)
211 0 : osTableName = osTableID;
212 : else
213 0 : osTableName = CPLSPrintf("Layer_%d", nLayers+1);
214 : }
215 1 : CleanString(osTableName);
216 : CPLString osTableInterchangeFormat =
217 1 : oKeywords.GetKeyword( MakeAttr(osTableID, "INTERCHANGE_FORMAT"), "" );
218 1 : CPLString osTableRows = oKeywords.GetKeyword( MakeAttr(osTableID, "ROWS"), "" );
219 1 : int nRecords = atoi(osTableRows);
220 1 : if (osTableInterchangeFormat.size() == 0 ||
221 : osTableRows.size() == 0 || nRecords < 0)
222 : {
223 : CPLError(CE_Failure, CPLE_NotSupported,
224 0 : "One of TABLE.INTERCHANGE_FORMAT or TABLE.ROWS is missing");
225 0 : return FALSE;
226 : }
227 :
228 1 : CleanString(osTableInterchangeFormat);
229 1 : if (osTableInterchangeFormat.compare("ASCII") != 0 &&
230 : osTableInterchangeFormat.compare("BINARY") != 0)
231 : {
232 : CPLError(CE_Failure, CPLE_NotSupported,
233 0 : "Only INTERCHANGE_FORMAT=ASCII or BINARY is supported");
234 0 : return FALSE;
235 : }
236 :
237 1 : FILE* fp = VSIFOpenL(osTableFilename, "rb");
238 1 : if (fp == NULL)
239 : {
240 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s",
241 0 : osTableFilename.c_str());
242 0 : return FALSE;
243 : }
244 :
245 1 : CPLString osTableStructure = oKeywords.GetKeyword( MakeAttr(osTableID, "^STRUCTURE"), "" );
246 1 : if (osTableStructure.size() != 0)
247 : {
248 1 : CPLString osTPath = CPLGetPath(pszFilename);
249 1 : CleanString( osTableStructure );
250 1 : osTableStructure = CPLFormCIFilename( osTPath, osTableStructure, NULL );
251 : }
252 :
253 1 : GByte* pabyRecord = (GByte*) VSIMalloc(nRecordSize + 1);
254 1 : if (pabyRecord == NULL)
255 : {
256 0 : VSIFCloseL(fp);
257 0 : return FALSE;
258 : }
259 1 : pabyRecord[nRecordSize] = 0;
260 :
261 1 : papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
262 : papoLayers[nLayers] = new OGRPDSLayer(osTableID, osTableName, fp,
263 : pszFilename,
264 : osTableStructure,
265 : nRecords, nStartBytes,
266 : nRecordSize, pabyRecord,
267 1 : osTableInterchangeFormat.compare("ASCII") == 0);
268 1 : nLayers++;
269 :
270 1 : return TRUE;
271 : }
272 :
273 : /************************************************************************/
274 : /* Open() */
275 : /************************************************************************/
276 :
277 10 : int OGRPDSDataSource::Open( const char * pszFilename, int bUpdateIn)
278 :
279 : {
280 10 : if (bUpdateIn)
281 : {
282 3 : return FALSE;
283 : }
284 :
285 7 : pszName = CPLStrdup( pszFilename );
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Determine what sort of object this is. */
289 : /* -------------------------------------------------------------------- */
290 : VSIStatBufL sStatBuf;
291 :
292 7 : if( VSIStatL( pszFilename, &sStatBuf ) != 0 &&
293 : VSI_ISREG(sStatBuf.st_mode) )
294 0 : return FALSE;
295 :
296 : // --------------------------------------------------------------------
297 : // Does this appear to be a .PDS table file?
298 : // --------------------------------------------------------------------
299 :
300 7 : FILE* fp = VSIFOpenL(pszFilename, "rb");
301 7 : if (fp == NULL)
302 2 : return FALSE;
303 :
304 : char szBuffer[512];
305 5 : int nbRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
306 5 : szBuffer[nbRead] = '\0';
307 :
308 5 : const char* pszPos = strstr(szBuffer, "PDS_VERSION_ID");
309 5 : int bIsPDS = (pszPos != NULL);
310 :
311 5 : if (!bIsPDS)
312 : {
313 4 : VSIFCloseL(fp);
314 4 : return FALSE;
315 : }
316 :
317 1 : if (!oKeywords.Ingest(fp, pszPos - szBuffer))
318 : {
319 0 : VSIFCloseL(fp);
320 0 : return FALSE;
321 : }
322 :
323 1 : VSIFCloseL(fp);
324 1 : CPLString osRecordType = oKeywords.GetKeyword( "RECORD_TYPE", "" );
325 1 : CPLString osFileRecords = oKeywords.GetKeyword( "FILE_RECORDS", "" );
326 1 : CPLString osRecordBytes = oKeywords.GetKeyword( "RECORD_BYTES", "" );
327 1 : int nRecordSize = atoi(osRecordBytes);
328 1 : if (osRecordType.size() == 0 || osFileRecords.size() == 0 ||
329 : osRecordBytes.size() == 0 || nRecordSize <= 0)
330 : {
331 : CPLError(CE_Failure, CPLE_NotSupported,
332 0 : "One of RECORD_TYPE, FILE_RECORDS or RECORD_BYTES is missing");
333 1 : return FALSE;
334 : }
335 1 : CleanString(osRecordType);
336 1 : if (osRecordType.compare("FIXED_LENGTH") != 0)
337 : {
338 : CPLError(CE_Failure, CPLE_NotSupported,
339 0 : "Only RECORD_TYPE=FIXED_LENGTH is supported");
340 0 : return FALSE;
341 : }
342 :
343 1 : CPLString osTable = oKeywords.GetKeyword( "^TABLE", "" );
344 1 : if (osTable.size() != 0)
345 1 : LoadTable(pszFilename, nRecordSize, "TABLE");
346 : else
347 : {
348 0 : FILE* fp = VSIFOpenL(pszFilename, "rb");
349 0 : if (fp == NULL)
350 0 : return FALSE;
351 :
352 0 : while(TRUE)
353 : {
354 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
355 0 : const char* pszLine = CPLReadLine2L(fp, 256, NULL);
356 0 : CPLPopErrorHandler();
357 0 : CPLErrorReset();
358 0 : if (pszLine == NULL)
359 0 : break;
360 : char** papszTokens =
361 0 : CSLTokenizeString2( pszLine, " =", CSLT_HONOURSTRINGS );
362 0 : int nTokens = CSLCount(papszTokens);
363 0 : if (nTokens == 2 &&
364 : papszTokens[0][0] == '^' &&
365 : strstr(papszTokens[0], "TABLE") != NULL)
366 : {
367 0 : LoadTable(pszFilename, nRecordSize, papszTokens[0] + 1);
368 : }
369 0 : CSLDestroy(papszTokens);
370 0 : papszTokens = NULL;
371 : }
372 0 : VSIFCloseL(fp);
373 : }
374 :
375 1 : return nLayers != 0;
376 : }
|