1 : /******************************************************************************
2 : * $Id: ogridrisilayer.cpp 25110 2012-10-13 13:53:53Z rouault $
3 : *
4 : * Project: Idrisi Translator
5 : * Purpose: Implements OGRIdrisiLayer class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2011, 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_idrisi.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "ogr_p.h"
34 : #include "ogr_srs_api.h"
35 :
36 : CPL_CVSID("$Id: ogridrisilayer.cpp 25110 2012-10-13 13:53:53Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRIdrisiLayer() */
40 : /************************************************************************/
41 :
42 3 : OGRIdrisiLayer::OGRIdrisiLayer( const char* pszFilename,
43 : const char* pszLayerName,
44 : VSILFILE* fp,
45 : OGRwkbGeometryType eGeomType,
46 3 : const char* pszWTKString )
47 :
48 : {
49 3 : this->fp = fp;
50 3 : this->eGeomType = eGeomType;
51 3 : nNextFID = 1;
52 3 : bEOF = FALSE;
53 3 : fpAVL = NULL;
54 :
55 3 : if (pszWTKString)
56 : {
57 3 : poSRS = new OGRSpatialReference();
58 3 : char* pszTmp = (char*)pszWTKString;
59 3 : poSRS->importFromWkt(&pszTmp);
60 : }
61 : else
62 0 : poSRS = NULL;
63 :
64 3 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
65 3 : poFeatureDefn->Reference();
66 3 : poFeatureDefn->SetGeomType( eGeomType );
67 :
68 3 : OGRFieldDefn oFieldDefn("id", OFTReal);
69 3 : poFeatureDefn->AddFieldDefn( &oFieldDefn );
70 :
71 3 : bExtentValid = FALSE;
72 3 : dfMinX = dfMinY = dfMaxX = dfMaxY = 0.0;
73 :
74 3 : VSIFSeekL( fp, 1, SEEK_SET );
75 3 : if (VSIFReadL( &nTotalFeatures, sizeof(unsigned int), 1, fp ) != 1)
76 0 : nTotalFeatures = 0;
77 : CPL_LSBPTR32(&nTotalFeatures);
78 :
79 3 : if (nTotalFeatures != 0)
80 : {
81 3 : if (!Detect_AVL_ADC(pszFilename))
82 : {
83 2 : if( fpAVL != NULL )
84 0 : VSIFCloseL( fpAVL );
85 2 : fpAVL = NULL;
86 : }
87 : }
88 :
89 3 : ResetReading();
90 3 : }
91 :
92 : /************************************************************************/
93 : /* ~OGRIdrisiLayer() */
94 : /************************************************************************/
95 :
96 3 : OGRIdrisiLayer::~OGRIdrisiLayer()
97 :
98 : {
99 3 : if( poSRS != NULL )
100 3 : poSRS->Release();
101 :
102 3 : poFeatureDefn->Release();
103 :
104 3 : VSIFCloseL( fp );
105 :
106 3 : if( fpAVL != NULL )
107 1 : VSIFCloseL( fpAVL );
108 3 : }
109 :
110 : /************************************************************************/
111 : /* Detect_AVL_ADC() */
112 : /************************************************************************/
113 :
114 3 : int OGRIdrisiLayer::Detect_AVL_ADC(const char* pszFilename)
115 : {
116 : // --------------------------------------------------------------------
117 : // Look for .adc file
118 : // --------------------------------------------------------------------
119 3 : const char* pszADCFilename = CPLResetExtension(pszFilename, "adc");
120 3 : VSILFILE* fpADC = VSIFOpenL(pszADCFilename, "rb");
121 3 : if (fpADC == NULL)
122 : {
123 2 : pszADCFilename = CPLResetExtension(pszFilename, "ADC");
124 2 : fpADC = VSIFOpenL(pszADCFilename, "rb");
125 : }
126 :
127 3 : char** papszADC = NULL;
128 3 : if (fpADC != NULL)
129 : {
130 1 : VSIFCloseL(fpADC);
131 1 : fpADC = NULL;
132 :
133 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
134 1 : papszADC = CSLLoad2(pszADCFilename, 1024, 256, NULL);
135 1 : CPLPopErrorHandler();
136 1 : CPLErrorReset();
137 : }
138 :
139 3 : if (papszADC == NULL)
140 2 : return FALSE;
141 :
142 1 : CSLSetNameValueSeparator( papszADC, ":" );
143 :
144 1 : const char *pszVersion = CSLFetchNameValue( papszADC, "file format " );
145 1 : if( pszVersion == NULL || !EQUAL( pszVersion, "IDRISI Values A.1" ) )
146 : {
147 0 : CSLDestroy( papszADC );
148 0 : return FALSE;
149 : }
150 :
151 1 : const char *pszFileType = CSLFetchNameValue( papszADC, "file type " );
152 1 : if( pszFileType == NULL || !EQUAL( pszFileType, "ascii" ) )
153 : {
154 0 : CPLDebug("IDRISI", ".adc file found, but file type != ascii");
155 0 : CSLDestroy( papszADC );
156 0 : return FALSE;
157 : }
158 :
159 1 : const char* pszRecords = CSLFetchNameValue( papszADC, "records " );
160 1 : if( pszRecords == NULL || atoi(pszRecords) != nTotalFeatures )
161 : {
162 : CPLDebug("IDRISI", ".adc file found, but 'records' not found or not "
163 0 : "consistant with feature number declared in .vdc");
164 0 : CSLDestroy( papszADC );
165 0 : return FALSE;
166 : }
167 :
168 1 : const char* pszFields = CSLFetchNameValue( papszADC, "fields " );
169 1 : if( pszFields == NULL || atoi(pszFields) <= 1 )
170 : {
171 0 : CPLDebug("IDRISI", ".adc file found, but 'fields' not found or invalid");
172 0 : CSLDestroy( papszADC );
173 0 : return FALSE;
174 : }
175 :
176 : // --------------------------------------------------------------------
177 : // Look for .avl file
178 : // --------------------------------------------------------------------
179 1 : const char* pszAVLFilename = CPLResetExtension(pszFilename, "avl");
180 1 : fpAVL = VSIFOpenL(pszAVLFilename, "rb");
181 1 : if (fpAVL == NULL)
182 : {
183 0 : pszAVLFilename = CPLResetExtension(pszFilename, "AVL");
184 0 : fpAVL = VSIFOpenL(pszAVLFilename, "rb");
185 : }
186 1 : if (fpAVL == NULL)
187 : {
188 0 : CSLDestroy( papszADC );
189 0 : return FALSE;
190 : }
191 :
192 : // --------------------------------------------------------------------
193 : // Build layer definition
194 : // --------------------------------------------------------------------
195 :
196 : int iCurField;
197 : char szKey[32];
198 :
199 1 : iCurField = 0;
200 1 : sprintf(szKey, "field %d ", iCurField);
201 :
202 1 : char** papszIter = papszADC;
203 : const char* pszLine;
204 1 : int bFieldFound = FALSE;
205 1 : CPLString osFieldName;
206 15 : while((pszLine = *papszIter) != NULL)
207 : {
208 : //CPLDebug("IDRISI", "%s", pszLine);
209 13 : if (strncmp(pszLine, szKey, strlen(szKey)) == 0)
210 : {
211 4 : const char* pszColon = strchr(pszLine, ':');
212 4 : if (pszColon)
213 : {
214 4 : osFieldName = pszColon + 1;
215 4 : bFieldFound = TRUE;
216 : }
217 : }
218 9 : else if (bFieldFound &&
219 : strncmp(pszLine, "data type :", strlen("data type :")) == 0)
220 : {
221 4 : const char* pszFieldType = pszLine + strlen("data type :");
222 :
223 : OGRFieldDefn oFieldDefn(osFieldName.c_str(),
224 : EQUAL(pszFieldType, "integer") ? OFTInteger :
225 4 : EQUAL(pszFieldType, "real") ? OFTReal : OFTString);
226 :
227 4 : if( iCurField == 0 && oFieldDefn.GetType() != OFTInteger )
228 : {
229 0 : CSLDestroy( papszADC );
230 0 : return FALSE;
231 : }
232 :
233 4 : if( iCurField != 0 )
234 3 : poFeatureDefn->AddFieldDefn( &oFieldDefn );
235 :
236 4 : iCurField ++;
237 4 : sprintf(szKey, "field %d ", iCurField);
238 : }
239 :
240 13 : papszIter++;
241 : }
242 :
243 1 : CSLDestroy(papszADC);
244 :
245 1 : return TRUE;
246 : }
247 :
248 : /************************************************************************/
249 : /* ResetReading() */
250 : /************************************************************************/
251 :
252 11 : void OGRIdrisiLayer::ResetReading()
253 :
254 : {
255 11 : nNextFID = 1;
256 11 : bEOF = FALSE;
257 11 : VSIFSeekL( fp, 0x105, SEEK_SET );
258 11 : if( fpAVL != NULL )
259 5 : VSIFSeekL( fpAVL, 0, SEEK_SET );
260 11 : }
261 :
262 : /************************************************************************/
263 : /* GetNextFeature() */
264 : /************************************************************************/
265 :
266 9 : OGRFeature *OGRIdrisiLayer::GetNextFeature()
267 : {
268 : OGRFeature *poFeature;
269 :
270 0 : while(TRUE)
271 : {
272 9 : if (bEOF)
273 0 : return NULL;
274 :
275 9 : poFeature = GetNextRawFeature();
276 9 : if (poFeature == NULL)
277 : {
278 3 : bEOF = TRUE;
279 3 : return NULL;
280 : }
281 :
282 6 : if((m_poFilterGeom == NULL
283 : || FilterGeometry( poFeature->GetGeometryRef() ) )
284 : && (m_poAttrQuery == NULL
285 : || m_poAttrQuery->Evaluate( poFeature )) )
286 : {
287 6 : return poFeature;
288 : }
289 : else
290 0 : delete poFeature;
291 : }
292 : }
293 :
294 : /************************************************************************/
295 : /* TestCapability() */
296 : /************************************************************************/
297 :
298 6 : int OGRIdrisiLayer::TestCapability( const char * pszCap )
299 :
300 : {
301 6 : if (EQUAL(pszCap, OLCFastFeatureCount))
302 3 : return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
303 :
304 3 : if (EQUAL(pszCap, OLCFastGetExtent))
305 3 : return bExtentValid;
306 :
307 0 : return FALSE;
308 : }
309 :
310 : /************************************************************************/
311 : /* GetNextRawFeature() */
312 : /************************************************************************/
313 :
314 15 : OGRFeature *OGRIdrisiLayer::GetNextRawFeature()
315 : {
316 6 : while(TRUE)
317 : {
318 15 : if (eGeomType == wkbPoint)
319 : {
320 : double dfId;
321 : double dfX, dfY;
322 7 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
323 : VSIFReadL(&dfX, sizeof(double), 1, fp) != 1 ||
324 : VSIFReadL(&dfY, sizeof(double), 1, fp) != 1)
325 : {
326 1 : return NULL;
327 : }
328 : CPL_LSBPTR64(&dfId);
329 : CPL_LSBPTR64(&dfX);
330 : CPL_LSBPTR64(&dfY);
331 :
332 6 : if (m_poFilterGeom != NULL &&
333 : (dfX < m_sFilterEnvelope.MinX ||
334 : dfX > m_sFilterEnvelope.MaxX ||
335 : dfY < m_sFilterEnvelope.MinY ||
336 : dfY > m_sFilterEnvelope.MaxY))
337 : {
338 3 : nNextFID ++;
339 3 : continue;
340 : }
341 :
342 3 : OGRPoint* poGeom = new OGRPoint(dfX, dfY);
343 3 : if (poSRS)
344 3 : poGeom->assignSpatialReference(poSRS);
345 3 : OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
346 3 : poFeature->SetField(0, dfId);
347 3 : poFeature->SetFID(nNextFID ++);
348 3 : poFeature->SetGeometryDirectly(poGeom);
349 3 : ReadAVLLine(poFeature);
350 3 : return poFeature;
351 : }
352 8 : else if (eGeomType == wkbLineString)
353 : {
354 : double dfId;
355 : double dfMinXShape, dfMaxXShape, dfMinYShape, dfMaxYShape;
356 : unsigned int nNodes;
357 :
358 5 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
359 : VSIFReadL(&dfMinXShape, sizeof(double), 1, fp) != 1 ||
360 : VSIFReadL(&dfMaxXShape, sizeof(double), 1, fp) != 1 ||
361 : VSIFReadL(&dfMinYShape, sizeof(double), 1, fp) != 1 ||
362 : VSIFReadL(&dfMaxYShape, sizeof(double), 1, fp) != 1)
363 : {
364 1 : return NULL;
365 : }
366 : CPL_LSBPTR64(&dfId);
367 : CPL_LSBPTR64(&dfMinXShape);
368 : CPL_LSBPTR64(&dfMaxXShape);
369 : CPL_LSBPTR64(&dfMinYShape);
370 : CPL_LSBPTR64(&dfMaxYShape);
371 :
372 4 : if (VSIFReadL(&nNodes, sizeof(unsigned int), 1, fp) != 1)
373 : {
374 0 : return NULL;
375 : }
376 : CPL_LSBPTR32(&nNodes);
377 :
378 4 : if (nNodes > 100 * 1000 * 1000)
379 0 : return NULL;
380 :
381 4 : if (m_poFilterGeom != NULL &&
382 : (dfMaxXShape < m_sFilterEnvelope.MinX ||
383 : dfMinXShape > m_sFilterEnvelope.MaxX ||
384 : dfMaxYShape < m_sFilterEnvelope.MinY ||
385 : dfMinYShape > m_sFilterEnvelope.MaxY))
386 : {
387 2 : nNextFID ++;
388 2 : VSIFSeekL(fp, sizeof(OGRRawPoint) * nNodes, SEEK_CUR);
389 2 : continue;
390 : }
391 :
392 2 : OGRRawPoint* poRawPoints = (OGRRawPoint*)VSIMalloc2(sizeof(OGRRawPoint), nNodes);
393 2 : if (poRawPoints == NULL)
394 : {
395 0 : return NULL;
396 : }
397 :
398 2 : if ((unsigned int)VSIFReadL(poRawPoints, sizeof(OGRRawPoint), nNodes, fp) != nNodes)
399 : {
400 0 : VSIFree(poRawPoints);
401 0 : return NULL;
402 : }
403 :
404 : #if defined(CPL_MSB)
405 : for(unsigned int iNode=0; iNode<nNodes; iNode++)
406 : {
407 : CPL_LSBPTR64(&poRawPoints[iNode].x);
408 : CPL_LSBPTR64(&poRawPoints[iNode].y);
409 : }
410 : #endif
411 :
412 2 : OGRLineString* poGeom = new OGRLineString();
413 2 : poGeom->setPoints(nNodes, poRawPoints, NULL);
414 :
415 2 : VSIFree(poRawPoints);
416 :
417 2 : if (poSRS)
418 2 : poGeom->assignSpatialReference(poSRS);
419 2 : OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
420 2 : poFeature->SetField(0, dfId);
421 2 : poFeature->SetFID(nNextFID ++);
422 2 : poFeature->SetGeometryDirectly(poGeom);
423 2 : ReadAVLLine(poFeature);
424 2 : return poFeature;
425 : }
426 : else /* if (eGeomType == wkbPolygon) */
427 : {
428 : double dfId;
429 : double dfMinXShape, dfMaxXShape, dfMinYShape, dfMaxYShape;
430 : unsigned int nParts;
431 : unsigned int nTotalNodes;
432 :
433 3 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
434 : VSIFReadL(&dfMinXShape, sizeof(double), 1, fp) != 1 ||
435 : VSIFReadL(&dfMaxXShape, sizeof(double), 1, fp) != 1 ||
436 : VSIFReadL(&dfMinYShape, sizeof(double), 1, fp) != 1 ||
437 : VSIFReadL(&dfMaxYShape, sizeof(double), 1, fp) != 1)
438 : {
439 1 : return NULL;
440 : }
441 : CPL_LSBPTR64(&dfId);
442 : CPL_LSBPTR64(&dfMinXShape);
443 : CPL_LSBPTR64(&dfMaxXShape);
444 : CPL_LSBPTR64(&dfMinYShape);
445 : CPL_LSBPTR64(&dfMaxYShape);
446 2 : if (VSIFReadL(&nParts, sizeof(unsigned int), 1, fp) != 1 ||
447 : VSIFReadL(&nTotalNodes, sizeof(unsigned int), 1, fp) != 1)
448 : {
449 0 : return NULL;
450 : }
451 : CPL_LSBPTR32(&nParts);
452 : CPL_LSBPTR32(&nTotalNodes);
453 :
454 2 : if (nParts > 100000 || nTotalNodes > 100 * 1000 * 1000)
455 0 : return NULL;
456 :
457 2 : if (m_poFilterGeom != NULL &&
458 : (dfMaxXShape < m_sFilterEnvelope.MinX ||
459 : dfMinXShape > m_sFilterEnvelope.MaxX ||
460 : dfMaxYShape < m_sFilterEnvelope.MinY ||
461 : dfMinYShape > m_sFilterEnvelope.MaxY))
462 : {
463 : unsigned int iPart;
464 3 : for(iPart = 0; iPart < nParts; iPart ++)
465 : {
466 : unsigned int nNodes;
467 2 : if (VSIFReadL(&nNodes, sizeof(unsigned int), 1, fp) != 1)
468 0 : return NULL;
469 : CPL_LSBPTR32(&nNodes);
470 2 : if (nNodes > nTotalNodes)
471 0 : return NULL;
472 2 : VSIFSeekL(fp, sizeof(OGRRawPoint) * nNodes, SEEK_CUR);
473 : }
474 1 : nNextFID ++;
475 1 : continue;
476 : }
477 :
478 1 : OGRRawPoint* poRawPoints = (OGRRawPoint*)VSIMalloc2(sizeof(OGRRawPoint), nTotalNodes);
479 1 : if (poRawPoints == NULL)
480 : {
481 0 : return NULL;
482 : }
483 :
484 : unsigned int iPart;
485 1 : OGRPolygon* poGeom = new OGRPolygon();
486 6 : for(iPart = 0; iPart < nParts; iPart ++)
487 : {
488 : unsigned int nNodes;
489 2 : if (VSIFReadL(&nNodes, sizeof(unsigned int), 1, fp) != 1)
490 : {
491 0 : VSIFree(poRawPoints);
492 0 : delete poGeom;
493 0 : return NULL;
494 : }
495 : CPL_LSBPTR32(&nNodes);
496 :
497 2 : if (nNodes > nTotalNodes ||
498 : (unsigned int)VSIFReadL(poRawPoints, sizeof(OGRRawPoint), nNodes, fp) != nNodes)
499 : {
500 0 : VSIFree(poRawPoints);
501 0 : delete poGeom;
502 0 : return NULL;
503 : }
504 :
505 : #if defined(CPL_MSB)
506 : for(unsigned int iNode=0; iNode<nNodes; iNode++)
507 : {
508 : CPL_LSBPTR64(&poRawPoints[iNode].x);
509 : CPL_LSBPTR64(&poRawPoints[iNode].y);
510 : }
511 : #endif
512 :
513 2 : OGRLinearRing* poLR = new OGRLinearRing();
514 2 : poGeom->addRingDirectly(poLR);
515 2 : poLR->setPoints(nNodes, poRawPoints, NULL);
516 : }
517 :
518 1 : VSIFree(poRawPoints);
519 :
520 1 : if (poSRS)
521 1 : poGeom->assignSpatialReference(poSRS);
522 1 : OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
523 1 : poFeature->SetField(0, dfId);
524 1 : poFeature->SetFID(nNextFID ++);
525 1 : poFeature->SetGeometryDirectly(poGeom);
526 1 : ReadAVLLine(poFeature);
527 1 : return poFeature;
528 : }
529 : }
530 : }
531 :
532 : /************************************************************************/
533 : /* ReadAVLLine() */
534 : /************************************************************************/
535 :
536 6 : void OGRIdrisiLayer::ReadAVLLine(OGRFeature* poFeature)
537 : {
538 6 : if (fpAVL == NULL)
539 3 : return;
540 :
541 3 : const char* pszLine = CPLReadLineL(fpAVL);
542 3 : if (pszLine == NULL)
543 0 : return;
544 :
545 3 : char** papszTokens = CSLTokenizeStringComplex(pszLine, "\t", TRUE, TRUE);
546 3 : if (CSLCount(papszTokens) == poFeatureDefn->GetFieldCount())
547 : {
548 3 : int nID = atoi(papszTokens[0]);
549 3 : if (nID == poFeature->GetFID())
550 : {
551 : int i;
552 8 : for(i=1;i<poFeatureDefn->GetFieldCount();i++)
553 : {
554 6 : poFeature->SetField(i, papszTokens[i]);
555 : }
556 : }
557 : }
558 3 : CSLDestroy(papszTokens);
559 : }
560 :
561 : /************************************************************************/
562 : /* SetExtent() */
563 : /************************************************************************/
564 :
565 3 : void OGRIdrisiLayer::SetExtent(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY)
566 : {
567 3 : bExtentValid = TRUE;
568 3 : this->dfMinX = dfMinX;
569 3 : this->dfMinY = dfMinY;
570 3 : this->dfMaxX = dfMaxX;
571 3 : this->dfMaxY = dfMaxY;
572 3 : }
573 :
574 : /************************************************************************/
575 : /* GetExtent() */
576 : /************************************************************************/
577 :
578 3 : OGRErr OGRIdrisiLayer::GetExtent(OGREnvelope *psExtent, int bForce)
579 : {
580 3 : if (!bExtentValid)
581 0 : return OGRLayer::GetExtent(psExtent, bForce);
582 :
583 3 : psExtent->MinX = dfMinX;
584 3 : psExtent->MinY = dfMinY;
585 3 : psExtent->MaxX = dfMaxX;
586 3 : psExtent->MaxY = dfMaxY;
587 3 : return OGRERR_NONE;
588 : }
589 :
590 : /************************************************************************/
591 : /* GetFeatureCount() */
592 : /************************************************************************/
593 :
594 3 : int OGRIdrisiLayer::GetFeatureCount( int bForce )
595 : {
596 3 : if (nTotalFeatures > 0 && m_poFilterGeom == NULL && m_poAttrQuery == NULL)
597 3 : return nTotalFeatures;
598 :
599 0 : return OGRLayer::GetFeatureCount(bForce);
600 : }
|