1 : /******************************************************************************
2 : * $Id: ogrpdsdatasource.cpp 23042 2011-09-04 15:07:22Z 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 23042 2011-09-04 15:07:22Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRPDSDataSource() */
38 : /************************************************************************/
39 :
40 85 : OGRPDSDataSource::OGRPDSDataSource()
41 :
42 : {
43 85 : papoLayers = NULL;
44 85 : nLayers = 0;
45 :
46 85 : pszName = NULL;
47 85 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRPDSDataSource() */
51 : /************************************************************************/
52 :
53 85 : OGRPDSDataSource::~OGRPDSDataSource()
54 :
55 : {
56 86 : for( int i = 0; i < nLayers; i++ )
57 1 : delete papoLayers[i];
58 85 : CPLFree( papoLayers );
59 :
60 85 : CPLFree( pszName );
61 85 : }
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 2 : const char * OGRPDSDataSource::GetKeywordSub( const char *pszPath,
92 : int iSubscript,
93 : 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 1 : int OGRPDSDataSource::LoadTable(const char* pszFilename,
160 : int nRecordSize,
161 : 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 : VSILFILE* 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 1 : 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 85 : int OGRPDSDataSource::Open( const char * pszFilename, int bUpdateIn)
278 :
279 : {
280 85 : if (bUpdateIn)
281 : {
282 13 : return FALSE;
283 : }
284 :
285 72 : pszName = CPLStrdup( pszFilename );
286 :
287 : // --------------------------------------------------------------------
288 : // Does this appear to be a .PDS table file?
289 : // --------------------------------------------------------------------
290 :
291 72 : VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
292 72 : if (fp == NULL)
293 36 : return FALSE;
294 :
295 : char szBuffer[512];
296 36 : int nbRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
297 36 : szBuffer[nbRead] = '\0';
298 :
299 36 : const char* pszPos = strstr(szBuffer, "PDS_VERSION_ID");
300 36 : int bIsPDS = (pszPos != NULL);
301 :
302 36 : if (!bIsPDS)
303 : {
304 35 : VSIFCloseL(fp);
305 35 : return FALSE;
306 : }
307 :
308 1 : if (!oKeywords.Ingest(fp, pszPos - szBuffer))
309 : {
310 0 : VSIFCloseL(fp);
311 0 : return FALSE;
312 : }
313 :
314 1 : VSIFCloseL(fp);
315 1 : CPLString osRecordType = oKeywords.GetKeyword( "RECORD_TYPE", "" );
316 1 : CPLString osFileRecords = oKeywords.GetKeyword( "FILE_RECORDS", "" );
317 1 : CPLString osRecordBytes = oKeywords.GetKeyword( "RECORD_BYTES", "" );
318 1 : int nRecordSize = atoi(osRecordBytes);
319 1 : if (osRecordType.size() == 0 || osFileRecords.size() == 0 ||
320 : osRecordBytes.size() == 0 || nRecordSize <= 0)
321 : {
322 : CPLError(CE_Failure, CPLE_NotSupported,
323 0 : "One of RECORD_TYPE, FILE_RECORDS or RECORD_BYTES is missing");
324 0 : return FALSE;
325 : }
326 1 : CleanString(osRecordType);
327 1 : if (osRecordType.compare("FIXED_LENGTH") != 0)
328 : {
329 : CPLError(CE_Failure, CPLE_NotSupported,
330 0 : "Only RECORD_TYPE=FIXED_LENGTH is supported");
331 0 : return FALSE;
332 : }
333 :
334 1 : CPLString osTable = oKeywords.GetKeyword( "^TABLE", "" );
335 1 : if (osTable.size() != 0)
336 1 : LoadTable(pszFilename, nRecordSize, "TABLE");
337 : else
338 : {
339 0 : VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
340 0 : if (fp == NULL)
341 0 : return FALSE;
342 :
343 0 : while(TRUE)
344 : {
345 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
346 0 : const char* pszLine = CPLReadLine2L(fp, 256, NULL);
347 0 : CPLPopErrorHandler();
348 0 : CPLErrorReset();
349 0 : if (pszLine == NULL)
350 : break;
351 : char** papszTokens =
352 0 : CSLTokenizeString2( pszLine, " =", CSLT_HONOURSTRINGS );
353 0 : int nTokens = CSLCount(papszTokens);
354 0 : if (nTokens == 2 &&
355 0 : papszTokens[0][0] == '^' &&
356 : strstr(papszTokens[0], "TABLE") != NULL)
357 : {
358 0 : LoadTable(pszFilename, nRecordSize, papszTokens[0] + 1);
359 : }
360 0 : CSLDestroy(papszTokens);
361 0 : papszTokens = NULL;
362 : }
363 0 : VSIFCloseL(fp);
364 : }
365 :
366 1 : return nLayers != 0;
367 : }
|