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