Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SXF Translator
4 : * Purpose: Definition of classes for OGR SXF Datasource.
5 : * Author: Ben Ahmed Daho Ali, bidandou(at)yahoo(dot)fr
6 : * Dmitry Baryshnikov, polimax@mail.ru
7 : * Alexandr Lisovenko, alexander.lisovenko@gmail.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2011, Ben Ahmed Daho Ali
11 : * Copyright (c) 2013, NextGIS
12 : * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
13 : * Copyright (c) 2019, NextGIS, <info@nextgis.com>
14 : *
15 : * SPDX-License-Identifier: MIT
16 : ****************************************************************************/
17 :
18 : #include "cpl_conv.h"
19 : #include "ogr_sxf.h"
20 : #include "cpl_string.h"
21 : #include "cpl_multiproc.h"
22 :
23 : #include <math.h>
24 : #include <map>
25 : #include <string>
26 :
27 : #ifdef EMBED_RESOURCE_FILES
28 : #include "embedded_resources.h"
29 : #endif
30 :
31 : // EPSG code range http://gis.stackexchange.com/a/18676/9904
32 : constexpr int MIN_EPSG = 1000;
33 : constexpr int MAX_EPSG = 32768;
34 :
35 : /************************************************************************/
36 : /* OGRSXFDataSource() */
37 : /************************************************************************/
38 :
39 6 : OGRSXFDataSource::OGRSXFDataSource()
40 : {
41 6 : memset(&oSXFPassport.informationFlags, 0,
42 : sizeof(oSXFPassport.informationFlags));
43 6 : }
44 :
45 : /************************************************************************/
46 : /* ~OGRSXFDataSource() */
47 : /************************************************************************/
48 :
49 12 : OGRSXFDataSource::~OGRSXFDataSource()
50 :
51 : {
52 6 : m_apoLayers.clear();
53 :
54 6 : if (nullptr != oSXFPassport.stMapDescription.pSpatRef)
55 : {
56 5 : oSXFPassport.stMapDescription.pSpatRef->Release();
57 : }
58 :
59 6 : CloseFile();
60 :
61 6 : if (hIOMutex != nullptr)
62 : {
63 1 : CPLDestroyMutex(hIOMutex);
64 1 : hIOMutex = nullptr;
65 : }
66 12 : }
67 :
68 : /************************************************************************/
69 : /* CloseFile() */
70 : /************************************************************************/
71 6 : void OGRSXFDataSource::CloseFile()
72 : {
73 6 : if (nullptr != fpSXF)
74 : {
75 5 : VSIFCloseL(fpSXF);
76 5 : fpSXF = nullptr;
77 : }
78 6 : }
79 :
80 : /************************************************************************/
81 : /* TestCapability() */
82 : /************************************************************************/
83 :
84 39 : int OGRSXFDataSource::TestCapability(const char *pszCap)
85 : {
86 39 : if (EQUAL(pszCap, ODsCZGeometries))
87 18 : return true;
88 :
89 21 : return false;
90 : }
91 :
92 : /************************************************************************/
93 : /* GetLayer() */
94 : /************************************************************************/
95 :
96 942 : OGRLayer *OGRSXFDataSource::GetLayer(int iLayer)
97 :
98 : {
99 942 : if (iLayer < 0 || iLayer >= GetLayerCount())
100 2 : return nullptr;
101 : else
102 940 : return m_apoLayers[iLayer].get();
103 : }
104 :
105 : /************************************************************************/
106 : /* Open() */
107 : /************************************************************************/
108 :
109 6 : int OGRSXFDataSource::Open(const char *pszFilename, bool bUpdateIn,
110 : const char *const *papszOpenOpts)
111 : {
112 6 : if (bUpdateIn)
113 : {
114 1 : return FALSE;
115 : }
116 :
117 5 : fpSXF = VSIFOpenL(pszFilename, "rb");
118 5 : if (fpSXF == nullptr)
119 : {
120 0 : CPLError(CE_Warning, CPLE_OpenFailed, "SXF open file %s failed",
121 : pszFilename);
122 0 : return FALSE;
123 : }
124 :
125 : // read header
126 5 : const int nFileHeaderSize = sizeof(SXFHeader);
127 : SXFHeader stSXFFileHeader;
128 : const size_t nObjectsRead =
129 5 : VSIFReadL(&stSXFFileHeader, nFileHeaderSize, 1, fpSXF);
130 :
131 5 : if (nObjectsRead != 1)
132 : {
133 0 : CPLError(CE_Failure, CPLE_None, "SXF head read failed");
134 0 : CloseFile();
135 0 : return FALSE;
136 : }
137 5 : CPL_LSBPTR32(&(stSXFFileHeader.nHeaderLength));
138 5 : CPL_LSBPTR32(&(stSXFFileHeader.nCheckSum));
139 :
140 : // check version
141 5 : oSXFPassport.version = 0;
142 5 : if (stSXFFileHeader.nHeaderLength > 256) // if size == 400 then version >=
143 : // 4
144 : {
145 5 : oSXFPassport.version = stSXFFileHeader.nFormatVersion[2];
146 : }
147 : else
148 : {
149 0 : oSXFPassport.version = stSXFFileHeader.nFormatVersion[1];
150 : }
151 :
152 5 : if (oSXFPassport.version < 3)
153 : {
154 0 : CPLError(CE_Failure, CPLE_NotSupported,
155 : "SXF File version not supported");
156 0 : CloseFile();
157 0 : return FALSE;
158 : }
159 :
160 : // read description
161 5 : if (ReadSXFDescription(fpSXF, oSXFPassport) != OGRERR_NONE)
162 : {
163 0 : CPLError(CE_Failure, CPLE_NotSupported, "SXF. Wrong description.");
164 0 : CloseFile();
165 0 : return FALSE;
166 : }
167 :
168 : // read flags
169 5 : if (ReadSXFInformationFlags(fpSXF, oSXFPassport) != OGRERR_NONE)
170 : {
171 0 : CPLError(CE_Failure, CPLE_NotSupported,
172 : "SXF. Wrong state of the data.");
173 0 : CloseFile();
174 0 : return FALSE;
175 : }
176 :
177 5 : if (oSXFPassport.version == 3 &&
178 0 : oSXFPassport.informationFlags.bProjectionDataCompliance == false)
179 : {
180 0 : CPLError(CE_Failure, CPLE_NotSupported,
181 : "SXF. Data does not correspond to the projection.");
182 0 : CloseFile();
183 0 : return FALSE;
184 : }
185 :
186 : // read spatial data
187 5 : if (ReadSXFMapDescription(fpSXF, oSXFPassport, papszOpenOpts) !=
188 : OGRERR_NONE)
189 : {
190 0 : CPLError(CE_Failure, CPLE_NotSupported,
191 : "SXF. Wrong state of the data.");
192 0 : CloseFile();
193 0 : return FALSE;
194 : }
195 :
196 5 : if (oSXFPassport.informationFlags.bRealCoordinatesCompliance == false)
197 : {
198 5 : CPLError(CE_Warning, CPLE_NotSupported,
199 : "SXF. Given material may be rotated in the conditional system "
200 : "of coordinates");
201 : }
202 :
203 : /*---------------- TRY READ THE RSC FILE HEADER -----------------------*/
204 :
205 5 : CPLString soRSCRileName;
206 : const char *pszRSCRileName =
207 5 : CSLFetchNameValueDef(papszOpenOpts, "SXF_RSC_FILENAME",
208 : CPLGetConfigOption("SXF_RSC_FILENAME", ""));
209 10 : if (pszRSCRileName != nullptr &&
210 5 : CPLCheckForFile((char *)pszRSCRileName, nullptr) == TRUE)
211 : {
212 1 : soRSCRileName = pszRSCRileName;
213 : }
214 :
215 5 : if (soRSCRileName.empty())
216 : {
217 4 : pszRSCRileName = CPLResetExtension(pszFilename, "rsc");
218 4 : if (CPLCheckForFile((char *)pszRSCRileName, nullptr) == TRUE)
219 : {
220 0 : soRSCRileName = pszRSCRileName;
221 : }
222 : }
223 :
224 5 : if (soRSCRileName.empty())
225 : {
226 4 : pszRSCRileName = CPLResetExtension(pszFilename, "RSC");
227 4 : if (CPLCheckForFile((char *)pszRSCRileName, nullptr) == TRUE)
228 : {
229 0 : soRSCRileName = pszRSCRileName;
230 : }
231 : }
232 :
233 : // 1. Create layers from RSC file or create default set of layers from
234 : // gdal_data/default.rsc.
235 :
236 5 : VSILFILE *fpRSC = nullptr;
237 5 : if (soRSCRileName.empty())
238 : {
239 : #if defined(USE_ONLY_EMBEDDED_RESOURCE_FILES)
240 : pszRSCRileName = nullptr;
241 : #else
242 4 : pszRSCRileName = CPLFindFile("gdal", "default.rsc");
243 : #endif
244 : #ifdef EMBED_RESOURCE_FILES
245 : if (!pszRSCRileName || EQUAL(pszRSCRileName, "default.rsc"))
246 : {
247 : static const bool bOnce [[maybe_unused]] = []()
248 : {
249 : CPLDebug("SXF", "Using embedded default.rsc");
250 : return true;
251 : }();
252 : int sxf_default_rsc_size = 0;
253 : const unsigned char *sxf_default_rsc =
254 : SXFGetDefaultRSC(&sxf_default_rsc_size);
255 : fpRSC = VSIFileFromMemBuffer(
256 : nullptr,
257 : const_cast<GByte *>(
258 : reinterpret_cast<const GByte *>(sxf_default_rsc)),
259 : sxf_default_rsc_size,
260 : /* bTakeOwnership = */ false);
261 : }
262 : #endif
263 4 : if (nullptr != pszRSCRileName)
264 : {
265 4 : soRSCRileName = pszRSCRileName;
266 : }
267 : else
268 : {
269 0 : CPLDebug("OGRSXFDataSource", "Default RSC file not found");
270 : }
271 : }
272 :
273 5 : if (soRSCRileName.empty()
274 : #ifdef EMBED_RESOURCE_FILES
275 : && !fpRSC
276 : #endif
277 : )
278 : {
279 0 : CPLError(CE_Warning, CPLE_None, "RSC file for %s not exist",
280 : pszFilename);
281 : }
282 : else
283 : {
284 : #ifdef EMBED_RESOURCE_FILES
285 : if (!fpRSC)
286 : #endif
287 : {
288 5 : fpRSC = VSIFOpenL(soRSCRileName, "rb");
289 : }
290 5 : if (fpRSC == nullptr)
291 : {
292 0 : CPLError(CE_Warning, CPLE_OpenFailed, "RSC file %s open failed",
293 : soRSCRileName.c_str());
294 : }
295 : else
296 : {
297 5 : CPLDebug("OGRSXFDataSource", "RSC Filename: %s",
298 : soRSCRileName.c_str());
299 5 : CreateLayers(fpRSC, papszOpenOpts);
300 5 : VSIFCloseL(fpRSC);
301 : }
302 : }
303 :
304 5 : if (m_apoLayers.empty()) // create default set of layers
305 : {
306 1 : CreateLayers();
307 : }
308 :
309 5 : FillLayers();
310 :
311 5 : return TRUE;
312 : }
313 :
314 5 : OGRErr OGRSXFDataSource::ReadSXFDescription(VSILFILE *fpSXFIn,
315 : SXFPassport &passport)
316 : {
317 : // int nObjectsRead = 0;
318 :
319 5 : if (passport.version == 3)
320 : {
321 : // 78
322 : GByte buff[62];
323 0 : /* nObjectsRead = */ VSIFReadL(&buff, 62, 1, fpSXFIn);
324 0 : char date[3] = {0};
325 :
326 : // read year
327 0 : memcpy(date, buff, 2);
328 0 : passport.dtCrateDate.nYear = static_cast<GUInt16>(atoi(date));
329 0 : if (passport.dtCrateDate.nYear < 50)
330 0 : passport.dtCrateDate.nYear += 2000;
331 : else
332 0 : passport.dtCrateDate.nYear += 1900;
333 :
334 0 : memcpy(date, buff + 2, 2);
335 :
336 0 : passport.dtCrateDate.nMonth = static_cast<GUInt16>(atoi(date));
337 :
338 0 : memcpy(date, buff + 4, 2);
339 :
340 0 : passport.dtCrateDate.nDay = static_cast<GUInt16>(atoi(date));
341 :
342 0 : char szName[26] = {0};
343 0 : memcpy(szName, buff + 8, 24);
344 0 : szName[sizeof(szName) - 1] = '\0';
345 : char *pszRecoded =
346 0 : CPLRecode(szName, "CP1251", CPL_ENC_UTF8); // szName + 2
347 : passport.sMapSheet =
348 0 : pszRecoded; // TODO: check the encoding in SXF created in Linux
349 0 : CPLFree(pszRecoded);
350 :
351 0 : memcpy(&passport.nScale, buff + 32, 4);
352 0 : CPL_LSBPTR32(&passport.nScale);
353 :
354 0 : memcpy(szName, buff + 36, 26);
355 0 : szName[sizeof(szName) - 1] = '\0';
356 0 : pszRecoded = CPLRecode(szName, "CP866", CPL_ENC_UTF8);
357 : passport.sMapSheetName =
358 0 : pszRecoded; // TODO: check the encoding in SXF created in Linux
359 0 : CPLFree(pszRecoded);
360 : }
361 5 : else if (passport.version == 4)
362 : {
363 : // 96
364 : GByte buff[80];
365 5 : /* nObjectsRead = */ VSIFReadL(&buff, 80, 1, fpSXFIn);
366 5 : char date[5] = {0};
367 :
368 : // read year
369 5 : memcpy(date, buff, 4);
370 5 : passport.dtCrateDate.nYear = static_cast<GUInt16>(atoi(date));
371 :
372 5 : memcpy(date, buff + 4, 2);
373 5 : memset(date + 2, 0, 3);
374 :
375 5 : passport.dtCrateDate.nMonth = static_cast<GUInt16>(atoi(date));
376 :
377 5 : memcpy(date, buff + 6, 2);
378 :
379 5 : passport.dtCrateDate.nDay = static_cast<GUInt16>(atoi(date));
380 :
381 5 : char szName[32] = {0};
382 5 : memcpy(szName, buff + 12, 32);
383 5 : szName[sizeof(szName) - 1] = '\0';
384 : char *pszRecoded =
385 5 : CPLRecode(szName, "CP1251", CPL_ENC_UTF8); // szName + 2
386 : passport.sMapSheet =
387 5 : pszRecoded; // TODO: check the encoding in SXF created in Linux
388 5 : CPLFree(pszRecoded);
389 :
390 5 : memcpy(&passport.nScale, buff + 44, 4);
391 5 : CPL_LSBPTR32(&passport.nScale);
392 :
393 5 : memcpy(szName, buff + 48, 32);
394 5 : szName[sizeof(szName) - 1] = '\0';
395 5 : pszRecoded = CPLRecode(szName, "CP1251", CPL_ENC_UTF8);
396 : passport.sMapSheetName =
397 5 : pszRecoded; // TODO: check the encoding in SXF created in Linux
398 5 : CPLFree(pszRecoded);
399 : }
400 :
401 5 : SetMetadataItem("SHEET", passport.sMapSheet);
402 5 : SetMetadataItem("SHEET_NAME", passport.sMapSheetName);
403 5 : SetMetadataItem("SHEET_CREATE_DATE",
404 5 : CPLSPrintf("%.2u-%.2u-%.4u", passport.dtCrateDate.nDay,
405 5 : passport.dtCrateDate.nMonth,
406 5 : passport.dtCrateDate.nYear));
407 5 : SetMetadataItem("SXF_VERSION", CPLSPrintf("%u", passport.version));
408 5 : SetMetadataItem("SCALE", CPLSPrintf("1 : %u", passport.nScale));
409 :
410 5 : return OGRERR_NONE;
411 : }
412 :
413 5 : OGRErr OGRSXFDataSource::ReadSXFInformationFlags(VSILFILE *fpSXFIn,
414 : SXFPassport &passport)
415 : {
416 : // int nObjectsRead = 0;
417 : GByte val[4];
418 5 : /* nObjectsRead = */ VSIFReadL(&val, 4, 1, fpSXFIn);
419 :
420 5 : if (!(CHECK_BIT(val[0], 0) && CHECK_BIT(val[0], 1))) // xxxxxx11
421 : {
422 0 : return OGRERR_UNSUPPORTED_OPERATION;
423 : }
424 :
425 5 : if (CHECK_BIT(val[0], 2)) // xxxxx0xx or xxxxx1xx
426 : {
427 5 : passport.informationFlags.bProjectionDataCompliance = true;
428 : }
429 : else
430 : {
431 0 : passport.informationFlags.bProjectionDataCompliance = false;
432 : }
433 :
434 5 : if (CHECK_BIT(val[0], 4))
435 : {
436 0 : passport.informationFlags.bRealCoordinatesCompliance = true;
437 : }
438 : else
439 : {
440 5 : passport.informationFlags.bRealCoordinatesCompliance = false;
441 : }
442 :
443 5 : if (CHECK_BIT(val[0], 6))
444 : {
445 0 : passport.informationFlags.stCodingType = SXF_SEM_TXT;
446 : }
447 : else
448 : {
449 5 : if (CHECK_BIT(val[0], 5))
450 : {
451 0 : passport.informationFlags.stCodingType = SXF_SEM_HEX;
452 : }
453 : else
454 : {
455 5 : passport.informationFlags.stCodingType = SXF_SEM_DEC;
456 : }
457 : }
458 :
459 5 : if (CHECK_BIT(val[0], 7))
460 : {
461 0 : passport.informationFlags.stGenType = SXF_GT_LARGE_SCALE;
462 : }
463 : else
464 : {
465 5 : passport.informationFlags.stGenType = SXF_GT_SMALL_SCALE;
466 : }
467 :
468 : // version specific
469 :
470 5 : if (passport.version == 3)
471 : {
472 : // degrees are ints * 100 000 000
473 : // meters are ints / 10
474 0 : passport.informationFlags.stEnc = SXF_ENC_DOS;
475 0 : passport.informationFlags.stCoordAcc = SXF_COORD_ACC_DM;
476 0 : passport.informationFlags.bSort = false;
477 : }
478 5 : else if (passport.version == 4)
479 : {
480 5 : if (val[1] <= SXF_ENC_LAST)
481 : {
482 5 : passport.informationFlags.stEnc =
483 5 : static_cast<SXFTextEncoding>(val[1]);
484 : }
485 : else
486 : {
487 0 : CPLDebug("SXF",
488 : "Invalid passport.informationFlags.stEnc = %d. "
489 : "Defaulting to SXF_ENC_DOS",
490 0 : val[1]);
491 0 : passport.informationFlags.stEnc = SXF_ENC_DOS;
492 : }
493 :
494 5 : if (val[2] <= SXF_COORD_ACC_LAST)
495 : {
496 5 : passport.informationFlags.stCoordAcc =
497 5 : static_cast<SXFCoordinatesAccuracy>(val[2]);
498 : }
499 : else
500 : {
501 0 : CPLDebug("SXF",
502 : "Invalid passport.informationFlags.stCoordAcc = %d. "
503 : "Defaulting to SXF_COORD_ACC_UNDEFINED",
504 0 : val[1]);
505 0 : passport.informationFlags.stCoordAcc = SXF_COORD_ACC_UNDEFINED;
506 : }
507 :
508 5 : if (CHECK_BIT(val[3], 0))
509 : {
510 0 : passport.informationFlags.bSort = true;
511 : }
512 : else
513 : {
514 5 : passport.informationFlags.bSort = false;
515 : }
516 : }
517 :
518 5 : return OGRERR_NONE;
519 : }
520 :
521 5 : void OGRSXFDataSource::SetVertCS(const long iVCS, SXFPassport &passport,
522 : const char *const *papszOpenOpts)
523 : {
524 : const char *pszSetVertCS =
525 5 : CSLFetchNameValueDef(papszOpenOpts, "SXF_SET_VERTCS",
526 : CPLGetConfigOption("SXF_SET_VERTCS", "NO"));
527 5 : if (!CPLTestBool(pszSetVertCS))
528 5 : return;
529 :
530 0 : passport.stMapDescription.pSpatRef->importVertCSFromPanorama(
531 : static_cast<int>(iVCS));
532 : }
533 :
534 5 : OGRErr OGRSXFDataSource::ReadSXFMapDescription(VSILFILE *fpSXFIn,
535 : SXFPassport &passport,
536 : const char *const *papszOpenOpts)
537 : {
538 : // int nObjectsRead = 0;
539 5 : passport.stMapDescription.Env.MaxX = -100000000;
540 5 : passport.stMapDescription.Env.MinX = 100000000;
541 5 : passport.stMapDescription.Env.MaxY = -100000000;
542 5 : passport.stMapDescription.Env.MinY = 100000000;
543 :
544 5 : bool bIsX = true; // passport.informationFlags.bRealCoordinatesCompliance;
545 : // //if real coordinates we need to swap x & y
546 :
547 : // version specific
548 5 : if (passport.version == 3)
549 : {
550 : short nNoObjClass, nNoSemClass;
551 0 : if (VSIFReadL(&nNoObjClass, 2, 1, fpSXFIn) != 1)
552 0 : return OGRERR_FAILURE;
553 0 : if (VSIFReadL(&nNoSemClass, 2, 1, fpSXFIn) != 1)
554 0 : return OGRERR_FAILURE;
555 : GByte byMask[8];
556 0 : if (VSIFReadL(&byMask, 8, 1, fpSXFIn) != 1)
557 0 : return OGRERR_FAILURE;
558 :
559 : int nCorners[8];
560 :
561 : // get projected corner coords
562 0 : if (VSIFReadL(&nCorners, 32, 1, fpSXFIn) != 1)
563 0 : return OGRERR_FAILURE;
564 :
565 0 : for (int i = 0; i < 8; i++)
566 : {
567 0 : CPL_LSBPTR32(&nCorners[i]);
568 0 : passport.stMapDescription.stProjCoords[i] =
569 0 : double(nCorners[i]) / 10.0;
570 0 : if (bIsX) // X
571 : {
572 0 : if (passport.stMapDescription.Env.MaxY <
573 0 : passport.stMapDescription.stProjCoords[i])
574 0 : passport.stMapDescription.Env.MaxY =
575 0 : passport.stMapDescription.stProjCoords[i];
576 0 : if (passport.stMapDescription.Env.MinY >
577 0 : passport.stMapDescription.stProjCoords[i])
578 0 : passport.stMapDescription.Env.MinY =
579 0 : passport.stMapDescription.stProjCoords[i];
580 : }
581 : else
582 : {
583 0 : if (passport.stMapDescription.Env.MaxX <
584 0 : passport.stMapDescription.stProjCoords[i])
585 0 : passport.stMapDescription.Env.MaxX =
586 0 : passport.stMapDescription.stProjCoords[i];
587 0 : if (passport.stMapDescription.Env.MinX >
588 0 : passport.stMapDescription.stProjCoords[i])
589 0 : passport.stMapDescription.Env.MinX =
590 0 : passport.stMapDescription.stProjCoords[i];
591 : }
592 0 : bIsX = !bIsX;
593 : }
594 : // get geographic corner coords
595 0 : if (VSIFReadL(&nCorners, 32, 1, fpSXFIn) != 1)
596 0 : return OGRERR_FAILURE;
597 :
598 0 : for (int i = 0; i < 8; i++)
599 : {
600 0 : CPL_LSBPTR32(&nCorners[i]);
601 0 : passport.stMapDescription.stGeoCoords[i] =
602 0 : double(nCorners[i]) *
603 : 0.00000057295779513082; // from radians to degree * 100 000 000
604 : }
605 : }
606 5 : else if (passport.version == 4)
607 : {
608 5 : int nEPSG = 0;
609 5 : if (VSIFReadL(&nEPSG, 4, 1, fpSXFIn) != 1)
610 0 : return OGRERR_FAILURE;
611 5 : CPL_LSBPTR32(&nEPSG);
612 :
613 5 : if (nEPSG >= MIN_EPSG &&
614 0 : nEPSG <= MAX_EPSG) // TODO: check epsg valid range
615 : {
616 0 : passport.stMapDescription.pSpatRef = new OGRSpatialReference();
617 0 : passport.stMapDescription.pSpatRef->importFromEPSG(nEPSG);
618 : }
619 :
620 : double dfCorners[8];
621 5 : if (VSIFReadL(&dfCorners, 64, 1, fpSXFIn) != 1)
622 0 : return OGRERR_FAILURE;
623 :
624 45 : for (int i = 0; i < 8; i++)
625 : {
626 40 : CPL_LSBPTR64(&dfCorners[i]);
627 40 : passport.stMapDescription.stProjCoords[i] = dfCorners[i];
628 40 : if (bIsX) // X
629 : {
630 20 : if (passport.stMapDescription.Env.MaxY <
631 20 : passport.stMapDescription.stProjCoords[i])
632 10 : passport.stMapDescription.Env.MaxY =
633 10 : passport.stMapDescription.stProjCoords[i];
634 20 : if (passport.stMapDescription.Env.MinY >
635 20 : passport.stMapDescription.stProjCoords[i])
636 10 : passport.stMapDescription.Env.MinY =
637 10 : passport.stMapDescription.stProjCoords[i];
638 : }
639 : else
640 : {
641 20 : if (passport.stMapDescription.Env.MaxX <
642 20 : passport.stMapDescription.stProjCoords[i])
643 15 : passport.stMapDescription.Env.MaxX =
644 15 : passport.stMapDescription.stProjCoords[i];
645 20 : if (passport.stMapDescription.Env.MinX >
646 20 : passport.stMapDescription.stProjCoords[i])
647 5 : passport.stMapDescription.Env.MinX =
648 5 : passport.stMapDescription.stProjCoords[i];
649 : }
650 40 : bIsX = !bIsX;
651 : }
652 : // get geographic corner coords
653 5 : if (VSIFReadL(&dfCorners, 64, 1, fpSXFIn) != 1)
654 0 : return OGRERR_FAILURE;
655 :
656 45 : for (int i = 0; i < 8; i++)
657 : {
658 40 : CPL_LSBPTR64(&dfCorners[i]);
659 40 : passport.stMapDescription.stGeoCoords[i] =
660 40 : dfCorners[i] * TO_DEGREES; // to degree
661 : }
662 : }
663 :
664 5 : if (nullptr != passport.stMapDescription.pSpatRef)
665 : {
666 0 : return OGRERR_NONE;
667 : }
668 :
669 5 : GByte anData[8] = {0};
670 5 : if (VSIFReadL(&anData, 8, 1, fpSXFIn) != 1)
671 0 : return OGRERR_FAILURE;
672 5 : long iEllips = anData[0];
673 5 : long iVCS = anData[1];
674 5 : long iProjSys = anData[2];
675 : /* long iDatum = anData[3]; Unused. */
676 5 : double dfProjScale = 1;
677 :
678 5 : double adfPrjParams[8] = {0};
679 :
680 5 : if (passport.version == 3)
681 : {
682 0 : switch (anData[4])
683 : {
684 0 : case 1:
685 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_DECIMETRE;
686 0 : break;
687 0 : case 2:
688 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_CENTIMETRE;
689 0 : break;
690 0 : case 3:
691 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_MILLIMETRE;
692 0 : break;
693 0 : case 130:
694 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_RADIAN;
695 0 : break;
696 0 : case 129:
697 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_DEGREE;
698 0 : break;
699 0 : default:
700 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_METRE;
701 0 : break;
702 : }
703 :
704 0 : VSIFSeekL(fpSXFIn, 212, SEEK_SET);
705 :
706 : struct _buff
707 : {
708 : GUInt32 nRes;
709 : GInt16 anFrame[8];
710 : // cppcheck-suppress unusedStructMember
711 : GUInt32 nFrameCode;
712 : } buff;
713 :
714 0 : if (VSIFReadL(&buff, 20, 1, fpSXFIn) != 1)
715 0 : return OGRERR_FAILURE;
716 0 : CPL_LSBPTR32(&buff.nRes);
717 0 : CPL_LSBPTR32(&buff.nFrameCode);
718 0 : passport.stMapDescription.nResolution = buff.nRes; // resolution
719 :
720 0 : for (int i = 0; i < 8; i++)
721 : {
722 0 : CPL_LSBPTR16(&(buff.anFrame[i]));
723 0 : passport.stMapDescription.stFrameCoords[i] = buff.anFrame[i];
724 : }
725 :
726 : int anParams[5];
727 0 : if (VSIFReadL(&anParams, 20, 1, fpSXFIn) != 1)
728 0 : return OGRERR_FAILURE;
729 0 : for (int i = 0; i < 5; i++)
730 : {
731 0 : CPL_LSBPTR32(&anParams[i]);
732 : }
733 :
734 0 : if (anParams[0] != -1)
735 0 : dfProjScale = double(anParams[0]) / 100000000.0;
736 :
737 0 : if (anParams[2] != -1)
738 0 : passport.stMapDescription.dfXOr =
739 0 : double(anParams[2]) / 100000000.0 * TO_DEGREES;
740 : else
741 0 : passport.stMapDescription.dfXOr = 0;
742 :
743 0 : if (anParams[3] != -1)
744 0 : passport.stMapDescription.dfYOr =
745 0 : double(anParams[2]) / 100000000.0 * TO_DEGREES;
746 : else
747 0 : passport.stMapDescription.dfYOr = 0;
748 :
749 0 : passport.stMapDescription.dfFalseNorthing = 0;
750 0 : passport.stMapDescription.dfFalseEasting = 0;
751 :
752 : // adfPrjParams[0] = double(anParams[0]) / 100000000.0; // to radians
753 : // adfPrjParams[1] = double(anParams[1]) / 100000000.0;
754 : // adfPrjParams[2] = double(anParams[2]) / 100000000.0;
755 : // adfPrjParams[3] = double(anParams[3]) / 100000000.0;
756 0 : adfPrjParams[4] = dfProjScale; //?
757 : // adfPrjParams[5] = 0;//?
758 : // adfPrjParams[6] = 0;//?
759 : // adfPrjParams[7] = 0;// importFromPanorama calc it by itself
760 : }
761 5 : else if (passport.version == 4)
762 : {
763 5 : switch (anData[4])
764 : {
765 0 : case 64:
766 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_RADIAN;
767 0 : break;
768 0 : case 65:
769 0 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_DEGREE;
770 0 : break;
771 5 : default:
772 5 : passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_METRE;
773 5 : break;
774 : }
775 :
776 5 : VSIFSeekL(fpSXFIn, 312, SEEK_SET);
777 : GUInt32 buff[10];
778 5 : if (VSIFReadL(&buff, 40, 1, fpSXFIn) != 1)
779 0 : return OGRERR_FAILURE;
780 55 : for (int i = 0; i < 10; i++)
781 : {
782 50 : CPL_LSBPTR32(&buff[i]);
783 : }
784 :
785 5 : passport.stMapDescription.nResolution = buff[0]; // resolution
786 45 : for (int i = 0; i < 8; i++)
787 40 : passport.stMapDescription.stFrameCoords[i] = buff[1 + i];
788 :
789 5 : double adfParams[6] = {};
790 5 : if (VSIFReadL(&adfParams, 48, 1, fpSXFIn) != 1)
791 0 : return OGRERR_FAILURE;
792 35 : for (int i = 0; i < 6; i++)
793 : {
794 30 : CPL_LSBPTR64(&adfParams[i]);
795 : }
796 :
797 5 : if (adfParams[1] != -1)
798 5 : dfProjScale = adfParams[1];
799 5 : passport.stMapDescription.dfXOr = adfParams[2] * TO_DEGREES;
800 5 : passport.stMapDescription.dfYOr = adfParams[3] * TO_DEGREES;
801 5 : passport.stMapDescription.dfFalseNorthing = adfParams[4];
802 5 : passport.stMapDescription.dfFalseEasting = adfParams[5];
803 :
804 : // adfPrjParams[0] = adfParams[0]; // to radians
805 : // adfPrjParams[1] = adfParams[1];
806 : // adfPrjParams[2] = adfParams[2];
807 : // adfPrjParams[3] = adfParams[3];
808 5 : adfPrjParams[4] = dfProjScale; //?
809 : // adfPrjParams[5] = adfParams[4];
810 : // adfPrjParams[6] = adfParams[5];
811 : // adfPrjParams[7] = 0;// importFromPanorama calc it by itself
812 : }
813 :
814 5 : passport.stMapDescription.dfScale = passport.nScale;
815 :
816 5 : if (passport.stMapDescription.nResolution == 0)
817 : {
818 0 : return OGRERR_FAILURE;
819 : }
820 5 : const double dfCoeff = double(passport.stMapDescription.dfScale) /
821 5 : passport.stMapDescription.nResolution;
822 5 : passport.stMapDescription.bIsRealCoordinates =
823 5 : passport.informationFlags.bRealCoordinatesCompliance;
824 5 : passport.stMapDescription.stCoordAcc = passport.informationFlags.stCoordAcc;
825 :
826 5 : if (!passport.stMapDescription.bIsRealCoordinates)
827 : {
828 5 : if (passport.stMapDescription.stFrameCoords[0] == 0 &&
829 5 : passport.stMapDescription.stFrameCoords[1] == 0 &&
830 5 : passport.stMapDescription.stFrameCoords[2] == 0 &&
831 5 : passport.stMapDescription.stFrameCoords[3] == 0 &&
832 5 : passport.stMapDescription.stFrameCoords[4] == 0 &&
833 5 : passport.stMapDescription.stFrameCoords[5] == 0 &&
834 5 : passport.stMapDescription.stFrameCoords[6] == 0 &&
835 5 : passport.stMapDescription.stFrameCoords[7] == 0)
836 : {
837 5 : passport.stMapDescription.bIsRealCoordinates = true;
838 : }
839 : else
840 : {
841 : // origin
842 0 : passport.stMapDescription.dfXOr =
843 0 : passport.stMapDescription.stProjCoords[1] -
844 0 : passport.stMapDescription.stFrameCoords[1] * dfCoeff;
845 0 : passport.stMapDescription.dfYOr =
846 0 : passport.stMapDescription.stProjCoords[0] -
847 0 : passport.stMapDescription.stFrameCoords[0] * dfCoeff;
848 : }
849 : }
850 :
851 : // normalize some coordintatessystems
852 5 : if ((iEllips == 1 || iEllips == 0) &&
853 : iProjSys == 1) // Pulkovo 1942 / Gauss-Kruger
854 : {
855 5 : double dfCenterLongEnv =
856 5 : passport.stMapDescription.stGeoCoords[1] +
857 5 : fabs(passport.stMapDescription.stGeoCoords[5] -
858 5 : passport.stMapDescription.stGeoCoords[1]) /
859 : 2;
860 :
861 5 : int nZoneEnv = (int)((dfCenterLongEnv + 3.0) / 6.0 + 0.5);
862 :
863 5 : if (nZoneEnv > 1 && nZoneEnv < 33)
864 : {
865 5 : int nEPSG = 28400 + nZoneEnv;
866 5 : passport.stMapDescription.pSpatRef = new OGRSpatialReference();
867 5 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
868 : OAMS_TRADITIONAL_GIS_ORDER);
869 : OGRErr eErr =
870 5 : passport.stMapDescription.pSpatRef->importFromEPSG(nEPSG);
871 5 : SetVertCS(iVCS, passport, papszOpenOpts);
872 5 : return eErr;
873 : }
874 : else
875 : {
876 0 : adfPrjParams[7] = nZoneEnv;
877 :
878 0 : if (adfPrjParams[5] == 0) // False Easting
879 : {
880 0 : if (passport.stMapDescription.Env.MaxX < 500000)
881 0 : adfPrjParams[5] = 500000;
882 : else
883 : {
884 0 : if (nZoneEnv >= -60 && nZoneEnv <= 60)
885 0 : adfPrjParams[5] = nZoneEnv * 1000000 + 500000;
886 : else
887 : {
888 0 : CPLError(CE_Failure, CPLE_AppDefined,
889 : "Wrong nZoneEnv = %d value", nZoneEnv);
890 0 : return OGRERR_FAILURE;
891 : }
892 : }
893 : }
894 0 : }
895 : }
896 0 : else if (iEllips == 9 && iProjSys == 17) // WGS84 / UTM
897 : {
898 0 : double dfCenterLongEnv =
899 0 : passport.stMapDescription.stGeoCoords[1] +
900 0 : fabs(passport.stMapDescription.stGeoCoords[5] -
901 0 : passport.stMapDescription.stGeoCoords[1]) /
902 : 2;
903 0 : int nZoneEnv = (int)(30 + (dfCenterLongEnv + 3.0) / 6.0 + 0.5);
904 0 : bool bNorth = passport.stMapDescription.stGeoCoords[6] +
905 0 : (passport.stMapDescription.stGeoCoords[2] -
906 0 : passport.stMapDescription.stGeoCoords[6]) /
907 : 2 <
908 : 0;
909 0 : int nEPSG = 0;
910 0 : if (bNorth)
911 : {
912 0 : nEPSG = 32600 + nZoneEnv;
913 : }
914 : else
915 : {
916 0 : nEPSG = 32700 + nZoneEnv;
917 : }
918 0 : passport.stMapDescription.pSpatRef = new OGRSpatialReference();
919 0 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
920 : OAMS_TRADITIONAL_GIS_ORDER);
921 0 : OGRErr eErr = passport.stMapDescription.pSpatRef->importFromEPSG(nEPSG);
922 0 : SetVertCS(iVCS, passport, papszOpenOpts);
923 0 : return eErr;
924 : }
925 0 : else if (iEllips == 45 && iProjSys == 35) // Mercator 3857 on sphere wgs84
926 : {
927 0 : passport.stMapDescription.pSpatRef = new OGRSpatialReference(
928 : "PROJCS[\"WGS 84 / Pseudo-Mercator\",GEOGCS[\"WGS "
929 : "84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS "
930 : "84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],"
931 : "AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY["
932 : "\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY["
933 : "\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],PROJECTION["
934 : "\"Mercator_1SP\"],PARAMETER[\"central_meridian\",0],PARAMETER["
935 : "\"scale_factor\",1],PARAMETER[\"false_easting\",0],PARAMETER["
936 : "\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\","
937 : "\"9001\"]],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH],EXTENSION[\"PROJ4\","
938 : "\"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 "
939 : "+x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext "
940 0 : "+no_defs\"],AUTHORITY[\"EPSG\",\"3857\"]]");
941 0 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
942 : OAMS_TRADITIONAL_GIS_ORDER);
943 0 : OGRErr eErr =
944 : OGRERR_NONE; // passport.stMapDescription.pSpatRef->importFromEPSG(3857);
945 0 : SetVertCS(iVCS, passport, papszOpenOpts);
946 0 : return eErr;
947 : }
948 0 : else if (iEllips == 9 && iProjSys == 35) // Mercator 3395 on ellips wgs84
949 : {
950 0 : passport.stMapDescription.pSpatRef = new OGRSpatialReference();
951 0 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
952 : OAMS_TRADITIONAL_GIS_ORDER);
953 0 : OGRErr eErr = passport.stMapDescription.pSpatRef->importFromEPSG(3395);
954 0 : SetVertCS(iVCS, passport, papszOpenOpts);
955 0 : return eErr;
956 : }
957 0 : else if (iEllips == 9 && iProjSys == 34) // Miller 54003 on sphere wgs84
958 : {
959 0 : passport.stMapDescription.pSpatRef = new OGRSpatialReference(
960 : "PROJCS[\"World_Miller_Cylindrical\",GEOGCS[\"GCS_GLOBE\", "
961 : "DATUM[\"GLOBE\", SPHEROID[\"GLOBE\", 6367444.6571, "
962 : "0.0]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0."
963 : "017453292519943295]],PROJECTION[\"Miller_Cylindrical\"],PARAMETER["
964 : "\"False_Easting\",0],PARAMETER[\"False_Northing\",0],PARAMETER["
965 : "\"Central_Meridian\",0],UNIT[\"Meter\",1],AUTHORITY[\"EPSG\","
966 0 : "\"54003\"]]");
967 0 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
968 : OAMS_TRADITIONAL_GIS_ORDER);
969 0 : OGRErr eErr =
970 : OGRERR_NONE; // passport.stMapDescription.pSpatRef->importFromEPSG(3395);
971 : // OGRErr eErr =
972 : // passport.stMapDescription.pSpatRef->importFromEPSG(54003);
973 :
974 0 : SetVertCS(iVCS, passport, papszOpenOpts);
975 0 : return eErr;
976 : }
977 0 : else if (iEllips == 9 && iProjSys == 33 &&
978 0 : passport.stMapDescription.eUnitInPlan == SXF_COORD_MU_DEGREE)
979 : {
980 0 : passport.stMapDescription.pSpatRef =
981 0 : new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG);
982 0 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
983 : OAMS_TRADITIONAL_GIS_ORDER);
984 0 : OGRErr eErr = OGRERR_NONE;
985 0 : SetVertCS(iVCS, passport, papszOpenOpts);
986 0 : return eErr;
987 : }
988 :
989 : // TODO: Need to normalize more SRS:
990 : // PAN_PROJ_WAG1
991 : // PAN_PROJ_MERCAT
992 : // PAN_PROJ_PS
993 : // PAN_PROJ_POLYC
994 : // PAN_PROJ_EC
995 : // PAN_PROJ_LCC
996 : // PAN_PROJ_STEREO
997 : // PAN_PROJ_AE
998 : // PAN_PROJ_GNOMON
999 : // PAN_PROJ_MOLL
1000 : // PAN_PROJ_LAEA
1001 : // PAN_PROJ_EQC
1002 : // PAN_PROJ_CEA
1003 : // PAN_PROJ_IMWP
1004 : //
1005 :
1006 0 : passport.stMapDescription.pSpatRef = new OGRSpatialReference();
1007 0 : passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
1008 : OAMS_TRADITIONAL_GIS_ORDER);
1009 0 : OGRErr eErr = passport.stMapDescription.pSpatRef->importFromPanorama(
1010 0 : anData[2], anData[3], anData[0], adfPrjParams);
1011 0 : SetVertCS(iVCS, passport, papszOpenOpts);
1012 0 : return eErr;
1013 : }
1014 :
1015 5 : void OGRSXFDataSource::FillLayers()
1016 : {
1017 5 : CPLDebug("SXF", "Create layers");
1018 :
1019 : // 2. Read all records (only classify code and offset) and add this to
1020 : // correspondence layer
1021 5 : int nObjectsRead = 0;
1022 5 : vsi_l_offset nOffset = 0;
1023 :
1024 : // get record count
1025 5 : GUInt32 nRecordCountMax = 0;
1026 5 : if (oSXFPassport.version == 3)
1027 : {
1028 0 : VSIFSeekL(fpSXF, 288, SEEK_SET);
1029 0 : nObjectsRead =
1030 0 : static_cast<int>(VSIFReadL(&nRecordCountMax, 4, 1, fpSXF));
1031 0 : nOffset = 300;
1032 0 : CPL_LSBPTR32(&nRecordCountMax);
1033 : }
1034 5 : else if (oSXFPassport.version == 4)
1035 : {
1036 5 : VSIFSeekL(fpSXF, 440, SEEK_SET);
1037 5 : nObjectsRead =
1038 5 : static_cast<int>(VSIFReadL(&nRecordCountMax, 4, 1, fpSXF));
1039 5 : nOffset = 452;
1040 5 : CPL_LSBPTR32(&nRecordCountMax);
1041 : }
1042 : /* else nOffset and nObjectsRead will be 0 */
1043 :
1044 5 : if (nObjectsRead != 1)
1045 : {
1046 0 : CPLError(CE_Failure, CPLE_FileIO, "Get record count failed");
1047 0 : return;
1048 : }
1049 :
1050 5 : VSIFSeekL(fpSXF, nOffset, SEEK_SET);
1051 :
1052 395 : for (GUInt32 nFID = 0; nFID < nRecordCountMax; nFID++)
1053 : {
1054 : GInt32 buff[6];
1055 390 : nObjectsRead = static_cast<int>(VSIFReadL(&buff, 24, 1, fpSXF));
1056 2730 : for (int i = 0; i < 6; i++)
1057 : {
1058 2340 : CPL_LSBPTR32(&buff[i]);
1059 : }
1060 :
1061 390 : if (nObjectsRead != 1 || buff[0] != IDSXFOBJ)
1062 : {
1063 0 : CPLError(CE_Failure, CPLE_FileIO, "Read record %d failed", nFID);
1064 0 : return;
1065 : }
1066 :
1067 390 : bool bHasSemantic = CHECK_BIT(buff[5], 9);
1068 390 : if (bHasSemantic) // check has attributes
1069 : {
1070 : // we have already 24 byte read
1071 250 : vsi_l_offset nOffsetSemantic = 8 + buff[2];
1072 250 : VSIFSeekL(fpSXF, nOffsetSemantic, SEEK_CUR);
1073 : }
1074 :
1075 390 : int nSemanticSize = buff[1] - 32 - buff[2];
1076 390 : if (nSemanticSize < 0)
1077 : {
1078 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value");
1079 0 : break;
1080 : }
1081 :
1082 4643 : for (const auto &poLayer : m_apoLayers)
1083 : {
1084 4643 : if (poLayer->AddRecord(nFID, buff[3], nOffset, bHasSemantic,
1085 4643 : nSemanticSize) == TRUE)
1086 : {
1087 390 : break;
1088 : }
1089 : }
1090 390 : nOffset += buff[1];
1091 390 : VSIFSeekL(fpSXF, nOffset, SEEK_SET);
1092 : }
1093 : // 3. delete empty layers
1094 87 : for (size_t i = 0; i < m_apoLayers.size(); /* increment in loop */)
1095 : {
1096 82 : OGRSXFLayer *pOGRSXFLayer = m_apoLayers[i].get();
1097 82 : if (pOGRSXFLayer->GetFeatureCount() == 0)
1098 : {
1099 44 : m_apoLayers.erase(m_apoLayers.begin() + i);
1100 : }
1101 : else
1102 : {
1103 38 : pOGRSXFLayer->ResetReading();
1104 38 : ++i;
1105 : }
1106 : }
1107 : }
1108 :
1109 2140 : OGRSXFLayer *OGRSXFDataSource::GetLayerById(GByte nID)
1110 : {
1111 18820 : for (const auto &poLayer : m_apoLayers)
1112 : {
1113 18820 : if (poLayer->GetId() == nID)
1114 : {
1115 2140 : return poLayer.get();
1116 : }
1117 : }
1118 0 : return nullptr;
1119 : }
1120 :
1121 1 : void OGRSXFDataSource::CreateLayers()
1122 : {
1123 : // default layers set
1124 1 : m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
1125 2 : fpSXF, &hIOMutex, static_cast<GByte>(0), CPLString("SYSTEM"),
1126 2 : oSXFPassport.version, oSXFPassport.stMapDescription));
1127 1 : auto pLayer = m_apoLayers.back().get();
1128 :
1129 : // default codes
1130 15 : for (unsigned int i = 1000000001; i < 1000000015; i++)
1131 : {
1132 14 : pLayer->AddClassifyCode(i);
1133 : }
1134 1 : pLayer->AddClassifyCode(91000000);
1135 :
1136 1 : m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
1137 2 : fpSXF, &hIOMutex, static_cast<GByte>(255), CPLString("Not_Classified"),
1138 2 : oSXFPassport.version, oSXFPassport.stMapDescription));
1139 1 : }
1140 :
1141 5 : void OGRSXFDataSource::CreateLayers(VSILFILE *fpRSC,
1142 : const char *const *papszOpenOpts)
1143 : {
1144 :
1145 : RSCHeader stRSCFileHeader;
1146 : int nObjectsRead = static_cast<int>(
1147 5 : VSIFReadL(&stRSCFileHeader, sizeof(stRSCFileHeader), 1, fpRSC));
1148 :
1149 5 : if (nObjectsRead != 1)
1150 : {
1151 1 : CPLError(CE_Warning, CPLE_None, "RSC head read failed");
1152 1 : return;
1153 : }
1154 :
1155 4 : CPL_LSBPTR32(&(stRSCFileHeader.nFileLength));
1156 4 : CPL_LSBPTR32(&(stRSCFileHeader.nVersion));
1157 4 : CPL_LSBPTR32(&(stRSCFileHeader.nEncoding));
1158 4 : CPL_LSBPTR32(&(stRSCFileHeader.nFileState));
1159 4 : CPL_LSBPTR32(&(stRSCFileHeader.nFileModState));
1160 4 : CPL_LSBPTR32(&(stRSCFileHeader.nLang));
1161 4 : CPL_LSBPTR32(&(stRSCFileHeader.nNextID));
1162 4 : CPL_LSBPTR32(&(stRSCFileHeader.nScale));
1163 :
1164 : #define SWAP_SECTION(x) \
1165 : CPL_LSBPTR32(&(x.nOffset)); \
1166 : CPL_LSBPTR32(&(x.nLength)); \
1167 : CPL_LSBPTR32(&(x.nRecordCount));
1168 :
1169 4 : SWAP_SECTION(stRSCFileHeader.Objects);
1170 4 : SWAP_SECTION(stRSCFileHeader.Semantic);
1171 4 : SWAP_SECTION(stRSCFileHeader.ClassifySemantic);
1172 4 : SWAP_SECTION(stRSCFileHeader.Defaults);
1173 4 : SWAP_SECTION(stRSCFileHeader.Semantics);
1174 4 : SWAP_SECTION(stRSCFileHeader.Layers);
1175 4 : SWAP_SECTION(stRSCFileHeader.Limits);
1176 4 : SWAP_SECTION(stRSCFileHeader.Parameters);
1177 4 : SWAP_SECTION(stRSCFileHeader.Print);
1178 4 : SWAP_SECTION(stRSCFileHeader.Palettes);
1179 4 : SWAP_SECTION(stRSCFileHeader.Fonts);
1180 4 : SWAP_SECTION(stRSCFileHeader.Libs);
1181 4 : SWAP_SECTION(stRSCFileHeader.ImageParams);
1182 4 : SWAP_SECTION(stRSCFileHeader.Tables);
1183 4 : CPL_LSBPTR32(&(stRSCFileHeader.nFontEnc));
1184 4 : CPL_LSBPTR32(&(stRSCFileHeader.nColorsInPalette));
1185 :
1186 : GByte szLayersID[4];
1187 :
1188 : struct _layer
1189 : {
1190 : GUInt32 nLength;
1191 : char szName[32];
1192 : char szShortName[16];
1193 : GByte nNo;
1194 : // cppcheck-suppress unusedStructMember
1195 : GByte nPos;
1196 : // cppcheck-suppress unusedStructMember
1197 : GUInt16 nSemanticCount;
1198 : };
1199 :
1200 4 : VSIFSeekL(fpRSC, stRSCFileHeader.Layers.nOffset - sizeof(szLayersID),
1201 : SEEK_SET);
1202 4 : VSIFReadL(&szLayersID, sizeof(szLayersID), 1, fpRSC);
1203 4 : vsi_l_offset nOffset = stRSCFileHeader.Layers.nOffset;
1204 : _layer LAYER;
1205 :
1206 80 : for (GUInt32 i = 0; i < stRSCFileHeader.Layers.nRecordCount; ++i)
1207 : {
1208 76 : VSIFReadL(&LAYER, sizeof(LAYER), 1, fpRSC);
1209 76 : CPL_LSBPTR32(&(LAYER.nLength));
1210 76 : CPL_LSBPTR16(&(LAYER.nSemanticCount));
1211 76 : bool bLayerFullName = CPLTestBool(CSLFetchNameValueDef(
1212 : papszOpenOpts, "SXF_LAYER_FULLNAME",
1213 : CPLGetConfigOption("SXF_LAYER_FULLNAME", "NO")));
1214 76 : char *pszRecoded = nullptr;
1215 76 : if (bLayerFullName)
1216 : {
1217 19 : if (LAYER.szName[0] == 0)
1218 0 : pszRecoded = CPLStrdup("Unnamed");
1219 19 : else if (stRSCFileHeader.nFontEnc == 125)
1220 0 : pszRecoded = CPLRecode(LAYER.szName, "KOI8-R", CPL_ENC_UTF8);
1221 19 : else if (stRSCFileHeader.nFontEnc == 126)
1222 19 : pszRecoded = CPLRecode(LAYER.szName, "CP1251", CPL_ENC_UTF8);
1223 : else
1224 0 : pszRecoded = CPLStrdup(LAYER.szName);
1225 :
1226 19 : m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
1227 38 : fpSXF, &hIOMutex, LAYER.nNo, CPLString(pszRecoded),
1228 38 : oSXFPassport.version, oSXFPassport.stMapDescription));
1229 : }
1230 : else
1231 : {
1232 57 : if (LAYER.szShortName[0] == 0)
1233 0 : pszRecoded = CPLStrdup("Unnamed");
1234 57 : else if (stRSCFileHeader.nFontEnc == 125)
1235 : pszRecoded =
1236 0 : CPLRecode(LAYER.szShortName, "KOI8-R", CPL_ENC_UTF8);
1237 57 : else if (stRSCFileHeader.nFontEnc == 126)
1238 : pszRecoded =
1239 57 : CPLRecode(LAYER.szShortName, "CP1251", CPL_ENC_UTF8);
1240 : else
1241 0 : pszRecoded = CPLStrdup(LAYER.szShortName);
1242 :
1243 57 : m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
1244 114 : fpSXF, &hIOMutex, LAYER.nNo, CPLString(pszRecoded),
1245 114 : oSXFPassport.version, oSXFPassport.stMapDescription));
1246 : }
1247 76 : CPLFree(pszRecoded);
1248 :
1249 76 : nOffset += LAYER.nLength;
1250 76 : VSIFSeekL(fpRSC, nOffset, SEEK_SET);
1251 : }
1252 :
1253 4 : m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
1254 8 : fpSXF, &hIOMutex, static_cast<GByte>(255), CPLString("Not_Classified"),
1255 8 : oSXFPassport.version, oSXFPassport.stMapDescription));
1256 :
1257 : char szObjectsID[4];
1258 :
1259 : struct _object
1260 : {
1261 : unsigned nLength;
1262 : unsigned nClassifyCode;
1263 : // cppcheck-suppress unusedStructMember
1264 : unsigned nObjectNumber;
1265 : // cppcheck-suppress unusedStructMember
1266 : unsigned nObjectCode;
1267 : char szShortName[32];
1268 : char szName[32];
1269 : // cppcheck-suppress unusedStructMember
1270 : char szGeomType;
1271 : char szLayernNo;
1272 : // cppcheck-suppress unusedStructMember
1273 : char szUnimportantSeg[14];
1274 : };
1275 :
1276 4 : VSIFSeekL(fpRSC, stRSCFileHeader.Objects.nOffset - sizeof(szObjectsID),
1277 : SEEK_SET);
1278 4 : VSIFReadL(&szObjectsID, sizeof(szObjectsID), 1, fpRSC);
1279 4 : nOffset = stRSCFileHeader.Objects.nOffset;
1280 : _object OBJECT;
1281 :
1282 2144 : for (GUInt32 i = 0; i < stRSCFileHeader.Objects.nRecordCount; ++i)
1283 : {
1284 2140 : VSIFReadL(&OBJECT, sizeof(_object), 1, fpRSC);
1285 2140 : CPL_LSBPTR32(&(OBJECT.nLength));
1286 2140 : CPL_LSBPTR32(&(OBJECT.nClassifyCode));
1287 2140 : CPL_LSBPTR32(&(OBJECT.nObjectNumber));
1288 2140 : CPL_LSBPTR32(&(OBJECT.nObjectCode));
1289 :
1290 2140 : OGRSXFLayer *pLayer = GetLayerById(OBJECT.szLayernNo);
1291 2140 : if (nullptr != pLayer)
1292 : {
1293 2140 : char *pszRecoded = nullptr;
1294 2140 : if (OBJECT.szName[0] == 0)
1295 0 : pszRecoded = CPLStrdup("Unnamed");
1296 2140 : else if (stRSCFileHeader.nFontEnc == 125)
1297 0 : pszRecoded = CPLRecode(OBJECT.szName, "KOI8-R", CPL_ENC_UTF8);
1298 2140 : else if (stRSCFileHeader.nFontEnc == 126)
1299 2140 : pszRecoded = CPLRecode(OBJECT.szName, "CP1251", CPL_ENC_UTF8);
1300 : else
1301 : pszRecoded =
1302 0 : CPLStrdup(OBJECT.szName); // already in CPL_ENC_UTF8
1303 :
1304 2140 : pLayer->AddClassifyCode(OBJECT.nClassifyCode, pszRecoded);
1305 : // printf("%d;%s\n", OBJECT.nClassifyCode, OBJECT.szName);
1306 2140 : CPLFree(pszRecoded);
1307 : }
1308 :
1309 2140 : nOffset += OBJECT.nLength;
1310 2140 : VSIFSeekL(fpRSC, nOffset, SEEK_SET);
1311 : }
1312 : }
|