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