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 6 : std::string osADCFilename = CPLResetExtensionSafe(pszFilename, "adc");
93 3 : VSILFILE *fpADC = VSIFOpenL(osADCFilename.c_str(), "rb");
94 3 : if (fpADC == nullptr)
95 : {
96 2 : osADCFilename = CPLResetExtensionSafe(pszFilename, "ADC");
97 2 : fpADC = VSIFOpenL(osADCFilename.c_str(), "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(osADCFilename.c_str(), 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 2 : std::string osAVLFilename = CPLResetExtensionSafe(pszFilename, "avl");
154 1 : fpAVL = VSIFOpenL(osAVLFilename.c_str(), "rb");
155 1 : if (fpAVL == nullptr)
156 : {
157 0 : osAVLFilename = CPLResetExtensionSafe(pszFilename, "AVL");
158 0 : fpAVL = VSIFOpenL(osAVLFilename.c_str(), "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) const
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(
339 2 : fp, static_cast<vsi_l_offset>(sizeof(OGRRawPoint)) * nNodes,
340 : SEEK_CUR);
341 2 : continue;
342 : }
343 :
344 : OGRRawPoint *poRawPoints = static_cast<OGRRawPoint *>(
345 2 : VSI_MALLOC2_VERBOSE(sizeof(OGRRawPoint), nNodes));
346 2 : if (poRawPoints == nullptr)
347 : {
348 0 : bEOF = true;
349 0 : return nullptr;
350 : }
351 :
352 2 : if (static_cast<unsigned int>(VSIFReadL(
353 2 : poRawPoints, sizeof(OGRRawPoint), nNodes, fp)) != nNodes)
354 : {
355 0 : VSIFree(poRawPoints);
356 0 : bEOF = true;
357 0 : return nullptr;
358 : }
359 :
360 : #if defined(CPL_MSB)
361 : for (unsigned int iNode = 0; iNode < nNodes; iNode++)
362 : {
363 : CPL_LSBPTR64(&poRawPoints[iNode].x);
364 : CPL_LSBPTR64(&poRawPoints[iNode].y);
365 : }
366 : #endif
367 :
368 2 : OGRLineString *poGeom = new OGRLineString();
369 2 : poGeom->setPoints(nNodes, poRawPoints, nullptr);
370 :
371 2 : VSIFree(poRawPoints);
372 :
373 2 : if (poSRS)
374 2 : poGeom->assignSpatialReference(poSRS);
375 2 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
376 2 : poFeature->SetField(0, dfId);
377 2 : poFeature->SetFID(nNextFID++);
378 2 : poFeature->SetGeometryDirectly(poGeom);
379 2 : ReadAVLLine(poFeature);
380 2 : return poFeature;
381 : }
382 : else // if (eGeomType == wkbPolygon)
383 : {
384 5 : double dfId = 0.0;
385 5 : double dfMinXShape = 0.0;
386 5 : double dfMaxXShape = 0.0;
387 5 : double dfMinYShape = 0.0;
388 5 : double dfMaxYShape = 0.0;
389 :
390 5 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
391 4 : VSIFReadL(&dfMinXShape, sizeof(double), 1, fp) != 1 ||
392 4 : VSIFReadL(&dfMaxXShape, sizeof(double), 1, fp) != 1 ||
393 13 : VSIFReadL(&dfMinYShape, sizeof(double), 1, fp) != 1 ||
394 4 : VSIFReadL(&dfMaxYShape, sizeof(double), 1, fp) != 1)
395 : {
396 1 : bEOF = true;
397 3 : return nullptr;
398 : }
399 4 : CPL_LSBPTR64(&dfId);
400 4 : CPL_LSBPTR64(&dfMinXShape);
401 4 : CPL_LSBPTR64(&dfMaxXShape);
402 4 : CPL_LSBPTR64(&dfMinYShape);
403 4 : CPL_LSBPTR64(&dfMaxYShape);
404 4 : unsigned int nParts = 0;
405 4 : unsigned int nTotalNodes = 0;
406 8 : if (VSIFReadL(&nParts, sizeof(unsigned int), 1, fp) != 1 ||
407 4 : VSIFReadL(&nTotalNodes, sizeof(unsigned int), 1, fp) != 1)
408 : {
409 0 : bEOF = true;
410 0 : return nullptr;
411 : }
412 4 : CPL_LSBPTR32(&nParts);
413 4 : CPL_LSBPTR32(&nTotalNodes);
414 :
415 4 : if (nParts > 100000 || nTotalNodes > 100 * 1000 * 1000)
416 : {
417 0 : bEOF = true;
418 0 : return nullptr;
419 : }
420 :
421 4 : if (m_poFilterGeom != nullptr &&
422 2 : (dfMaxXShape < m_sFilterEnvelope.MinX ||
423 2 : dfMinXShape > m_sFilterEnvelope.MaxX ||
424 0 : dfMaxYShape < m_sFilterEnvelope.MinY ||
425 0 : dfMinYShape > m_sFilterEnvelope.MaxY))
426 : {
427 2 : VSIFSeekL(fp,
428 : static_cast<vsi_l_offset>(sizeof(unsigned int)) *
429 2 : nParts +
430 : static_cast<vsi_l_offset>(sizeof(OGRRawPoint)) *
431 2 : nTotalNodes,
432 : SEEK_CUR);
433 2 : nNextFID++;
434 2 : continue;
435 : }
436 :
437 : OGRRawPoint *poRawPoints = static_cast<OGRRawPoint *>(
438 2 : VSI_MALLOC2_VERBOSE(sizeof(OGRRawPoint), nTotalNodes));
439 2 : if (poRawPoints == nullptr)
440 : {
441 0 : bEOF = true;
442 0 : return nullptr;
443 : }
444 2 : unsigned int *panNodesCount = nullptr;
445 2 : if (nParts > 1)
446 : {
447 : panNodesCount = static_cast<unsigned int *>(
448 1 : CPLMalloc(sizeof(unsigned int) * nParts));
449 1 : if (VSIFReadL(panNodesCount, sizeof(unsigned int) * nParts, 1,
450 1 : fp) != 1)
451 : {
452 0 : VSIFree(poRawPoints);
453 0 : VSIFree(panNodesCount);
454 0 : bEOF = true;
455 0 : return nullptr;
456 : }
457 : #if defined(CPL_MSB)
458 : for (unsigned int iPart = 0; iPart < nParts; iPart++)
459 : {
460 : CPL_LSBPTR32(&panNodesCount[iPart]);
461 : }
462 : #endif
463 : }
464 : else
465 : {
466 1 : unsigned int nNodes = 0;
467 1 : if (VSIFReadL(&nNodes, sizeof(unsigned int) * nParts, 1, fp) !=
468 : 1)
469 : {
470 0 : VSIFree(poRawPoints);
471 0 : bEOF = true;
472 0 : return nullptr;
473 : }
474 1 : CPL_LSBPTR32(&nNodes);
475 1 : if (nNodes != nTotalNodes)
476 : {
477 0 : VSIFree(poRawPoints);
478 0 : bEOF = true;
479 0 : return nullptr;
480 : }
481 : }
482 :
483 2 : OGRPolygon *poGeom = new OGRPolygon();
484 5 : for (unsigned int iPart = 0; iPart < nParts; iPart++)
485 : {
486 3 : unsigned int nNodes =
487 3 : (nParts > 1) ? panNodesCount[iPart] : nTotalNodes;
488 6 : if (nNodes > nTotalNodes ||
489 3 : static_cast<unsigned int>(VSIFReadL(poRawPoints,
490 : sizeof(OGRRawPoint),
491 3 : nNodes, fp)) != nNodes)
492 : {
493 0 : VSIFree(poRawPoints);
494 0 : VSIFree(panNodesCount);
495 0 : delete poGeom;
496 0 : bEOF = true;
497 0 : return nullptr;
498 : }
499 :
500 : #if defined(CPL_MSB)
501 : for (unsigned int iNode = 0; iNode < nNodes; iNode++)
502 : {
503 : CPL_LSBPTR64(&poRawPoints[iNode].x);
504 : CPL_LSBPTR64(&poRawPoints[iNode].y);
505 : }
506 : #endif
507 :
508 3 : OGRLinearRing *poLR = new OGRLinearRing();
509 3 : poGeom->addRingDirectly(poLR);
510 3 : poLR->setPoints(nNodes, poRawPoints, nullptr);
511 : }
512 :
513 2 : VSIFree(poRawPoints);
514 2 : VSIFree(panNodesCount);
515 :
516 2 : if (poSRS)
517 2 : poGeom->assignSpatialReference(poSRS);
518 2 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
519 2 : poFeature->SetField(0, dfId);
520 2 : poFeature->SetFID(nNextFID++);
521 2 : poFeature->SetGeometryDirectly(poGeom);
522 2 : ReadAVLLine(poFeature);
523 2 : return poFeature;
524 : }
525 7 : }
526 : }
527 :
528 : /************************************************************************/
529 : /* ReadAVLLine() */
530 : /************************************************************************/
531 :
532 7 : void OGRIdrisiLayer::ReadAVLLine(OGRFeature *poFeature)
533 : {
534 7 : if (fpAVL == nullptr)
535 4 : return;
536 :
537 3 : const char *pszLine = CPLReadLineL(fpAVL);
538 3 : if (pszLine == nullptr)
539 0 : return;
540 :
541 3 : char **papszTokens = CSLTokenizeStringComplex(pszLine, "\t", TRUE, TRUE);
542 3 : if (CSLCount(papszTokens) == poFeatureDefn->GetFieldCount())
543 : {
544 3 : const int nID = atoi(papszTokens[0]);
545 3 : if (nID == poFeature->GetFID())
546 : {
547 8 : for (int i = 1; i < poFeatureDefn->GetFieldCount(); i++)
548 : {
549 6 : poFeature->SetField(i, papszTokens[i]);
550 : }
551 : }
552 : }
553 3 : CSLDestroy(papszTokens);
554 : }
555 :
556 : /************************************************************************/
557 : /* SetExtent() */
558 : /************************************************************************/
559 :
560 3 : void OGRIdrisiLayer::SetExtent(double dfMinXIn, double dfMinYIn,
561 : double dfMaxXIn, double dfMaxYIn)
562 : {
563 3 : bExtentValid = true;
564 3 : dfMinX = dfMinXIn;
565 3 : dfMinY = dfMinYIn;
566 3 : dfMaxX = dfMaxXIn;
567 3 : dfMaxY = dfMaxYIn;
568 3 : }
569 :
570 : /************************************************************************/
571 : /* IGetExtent() */
572 : /************************************************************************/
573 :
574 3 : OGRErr OGRIdrisiLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
575 : bool bForce)
576 : {
577 3 : if (!bExtentValid)
578 0 : return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
579 :
580 3 : psExtent->MinX = dfMinX;
581 3 : psExtent->MinY = dfMinY;
582 3 : psExtent->MaxX = dfMaxX;
583 3 : psExtent->MaxY = dfMaxY;
584 3 : return OGRERR_NONE;
585 : }
586 :
587 : /************************************************************************/
588 : /* GetFeatureCount() */
589 : /************************************************************************/
590 :
591 3 : GIntBig OGRIdrisiLayer::GetFeatureCount(int bForce)
592 : {
593 3 : if (nTotalFeatures > 0 && m_poFilterGeom == nullptr &&
594 3 : m_poAttrQuery == nullptr)
595 3 : return nTotalFeatures;
596 :
597 0 : return OGRLayer::GetFeatureCount(bForce);
598 : }
|