Coverage Report

Created: 2025-08-11 09:23

/src/gdal/ogr/ogrsf_frmts/sxf/ogrsxflayer.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  SXF Translator
4
 * Purpose:  Definition of classes for OGR SXF Layers.
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
 *
14
 * SPDX-License-Identifier: MIT
15
 ****************************************************************************/
16
17
#include "ogr_sxf.h"
18
#include "cpl_conv.h"
19
#include "cpl_string.h"
20
#include "ogr_p.h"
21
#include "ogr_srs_api.h"
22
#include "cpl_multiproc.h"
23
24
/************************************************************************/
25
/*                        OGRSXFLayer()                                 */
26
/************************************************************************/
27
28
OGRSXFLayer::OGRSXFLayer(VSILFILE *fp, CPLMutex **hIOMutex, GByte nID,
29
                         const char *pszLayerName, int nVer,
30
                         const SXFMapDescription &sxfMapDesc)
31
0
    : OGRLayer(), poFeatureDefn(new OGRFeatureDefn(pszLayerName)), fpSXF(fp),
32
0
      nLayerID(nID), stSXFMapDescription(sxfMapDesc), m_nSXFFormatVer(nVer),
33
0
      sFIDColumn_("ogc_fid"), m_hIOMutex(hIOMutex),
34
0
      m_dfCoeff(sxfMapDesc.nResolution == 0
35
0
                    ? 0.0
36
0
                    : sxfMapDesc.dfScale / sxfMapDesc.nResolution)
37
0
{
38
0
    stSXFMapDescription.pSpatRef->Reference();
39
0
    oNextIt = mnRecordDesc.begin();
40
0
    SetDescription(poFeatureDefn->GetName());
41
0
    poFeatureDefn->Reference();
42
43
0
    poFeatureDefn->SetGeomType(wkbUnknown);
44
0
    if (poFeatureDefn->GetGeomFieldCount() != 0)
45
0
        poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(
46
0
            stSXFMapDescription.pSpatRef);
47
48
0
    OGRFieldDefn oFIDField(sFIDColumn_, OFTInteger);
49
0
    poFeatureDefn->AddFieldDefn(&oFIDField);
50
51
0
    OGRFieldDefn oClCodeField("CLCODE", OFTInteger);
52
0
    oClCodeField.SetWidth(10);
53
0
    poFeatureDefn->AddFieldDefn(&oClCodeField);
54
55
0
    OGRFieldDefn oClNameField("CLNAME", OFTString);
56
0
    oClNameField.SetWidth(32);
57
0
    poFeatureDefn->AddFieldDefn(&oClNameField);
58
59
0
    OGRFieldDefn oNumField("OBJECTNUMB", OFTInteger);
60
0
    oNumField.SetWidth(10);
61
0
    poFeatureDefn->AddFieldDefn(&oNumField);
62
63
0
    OGRFieldDefn oAngField("ANGLE", OFTReal);
64
0
    poFeatureDefn->AddFieldDefn(&oAngField);
65
66
0
    OGRFieldDefn oTextField("TEXT", OFTString);
67
0
    oTextField.SetWidth(255);
68
0
    poFeatureDefn->AddFieldDefn(&oTextField);
69
0
}
70
71
/************************************************************************/
72
/*                         ~OGRSXFLayer()                               */
73
/************************************************************************/
74
75
OGRSXFLayer::~OGRSXFLayer()
76
0
{
77
0
    stSXFMapDescription.pSpatRef->Release();
78
0
    poFeatureDefn->Release();
79
0
}
80
81
/************************************************************************/
82
/*                AddClassifyCode(unsigned nClassCode)                  */
83
/* Add layer supported classify codes. Only records with this code can  */
84
/* be in layer                                                          */
85
/************************************************************************/
86
87
void OGRSXFLayer::AddClassifyCode(unsigned nClassCode, const char *szName)
88
0
{
89
0
    if (szName != nullptr)
90
0
    {
91
0
        mnClassificators[nClassCode] = CPLString(szName);
92
0
    }
93
0
    else
94
0
    {
95
0
        mnClassificators[nClassCode] = CPLString().Printf("%d", nClassCode);
96
0
    }
97
0
}
98
99
/************************************************************************/
100
/*                           AddRecord()                                */
101
/************************************************************************/
102
103
bool OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode,
104
                            vsi_l_offset nOffset, bool bHasSemantic,
105
                            size_t nSemanticsSize)
106
0
{
107
0
    if (mnClassificators.find(nClassCode) != mnClassificators.end() ||
108
0
        EQUAL(GetName(), "Not_Classified"))
109
0
    {
110
0
        mnRecordDesc[nFID] = nOffset;
111
        // Add additional semantics (attribute fields).
112
0
        if (bHasSemantic)
113
0
        {
114
0
            size_t offset = 0;
115
116
0
            while (offset < nSemanticsSize)
117
0
            {
118
0
                SXFRecordAttributeInfo stAttrInfo;
119
0
                bool bAddField = false;
120
0
                size_t nCurrOff = 0;
121
0
                int nReadObj =
122
0
                    static_cast<int>(VSIFReadL(&stAttrInfo, 4, 1, fpSXF));
123
0
                if (nReadObj == 1)
124
0
                {
125
0
                    CPL_LSBPTR16(&(stAttrInfo.nCode));
126
0
                    CPLString oFieldName;
127
0
                    if (snAttributeCodes.find(stAttrInfo.nCode) ==
128
0
                        snAttributeCodes.end())
129
0
                    {
130
0
                        bAddField = true;
131
0
                        snAttributeCodes.insert(stAttrInfo.nCode);
132
0
                        oFieldName.Printf("SC_%d", stAttrInfo.nCode);
133
0
                    }
134
135
0
                    SXFRecordAttributeType eType =
136
0
                        (SXFRecordAttributeType)stAttrInfo.nType;
137
138
0
                    offset += 4;
139
140
0
                    switch (eType)  // TODO: set field type form RSC as here
141
                                    // sometimes we have the codes and string
142
                                    // values can be get from RSC by this code
143
0
                    {
144
0
                        case SXF_RAT_ASCIIZ_DOS:
145
0
                        {
146
0
                            if (bAddField)
147
0
                            {
148
0
                                OGRFieldDefn oField(oFieldName, OFTString);
149
0
                                oField.SetWidth(255);
150
0
                                poFeatureDefn->AddFieldDefn(&oField);
151
0
                            }
152
0
                            offset += stAttrInfo.nScale + 1;
153
0
                            nCurrOff = stAttrInfo.nScale + 1;
154
0
                            break;
155
0
                        }
156
0
                        case SXF_RAT_ONEBYTE:
157
0
                        {
158
0
                            if (bAddField)
159
0
                            {
160
0
                                OGRFieldDefn oField(oFieldName, OFTReal);
161
0
                                poFeatureDefn->AddFieldDefn(&oField);
162
0
                            }
163
0
                            offset += 1;
164
0
                            nCurrOff = 1;
165
0
                            break;
166
0
                        }
167
0
                        case SXF_RAT_TWOBYTE:
168
0
                        {
169
0
                            if (bAddField)
170
0
                            {
171
0
                                OGRFieldDefn oField(oFieldName, OFTReal);
172
0
                                poFeatureDefn->AddFieldDefn(&oField);
173
0
                            }
174
0
                            offset += 2;
175
0
                            nCurrOff = 2;
176
0
                            break;
177
0
                        }
178
0
                        case SXF_RAT_FOURBYTE:
179
0
                        {
180
0
                            if (bAddField)
181
0
                            {
182
0
                                OGRFieldDefn oField(oFieldName, OFTReal);
183
0
                                poFeatureDefn->AddFieldDefn(&oField);
184
0
                            }
185
0
                            offset += 4;
186
0
                            nCurrOff = 4;
187
0
                            break;
188
0
                        }
189
0
                        case SXF_RAT_EIGHTBYTE:
190
0
                        {
191
0
                            if (bAddField)
192
0
                            {
193
0
                                OGRFieldDefn oField(oFieldName, OFTReal);
194
0
                                poFeatureDefn->AddFieldDefn(&oField);
195
0
                            }
196
0
                            offset += 8;
197
0
                            nCurrOff = 8;
198
0
                            break;
199
0
                        }
200
0
                        case SXF_RAT_ANSI_WIN:
201
0
                        {
202
0
                            if (bAddField)
203
0
                            {
204
0
                                OGRFieldDefn oField(oFieldName, OFTString);
205
0
                                oField.SetWidth(255);
206
0
                                poFeatureDefn->AddFieldDefn(&oField);
207
0
                            }
208
0
                            unsigned nLen = unsigned(stAttrInfo.nScale) + 1;
209
0
                            offset += nLen;
210
0
                            nCurrOff = nLen;
211
0
                            break;
212
0
                        }
213
0
                        case SXF_RAT_UNICODE:
214
0
                        {
215
0
                            if (bAddField)
216
0
                            {
217
0
                                OGRFieldDefn oField(oFieldName, OFTString);
218
0
                                oField.SetWidth(255);
219
0
                                poFeatureDefn->AddFieldDefn(&oField);
220
0
                            }
221
0
                            unsigned nLen =
222
0
                                (unsigned(stAttrInfo.nScale) + 1) * 2;
223
0
                            offset += nLen;
224
0
                            nCurrOff = nLen;
225
0
                            break;
226
0
                        }
227
0
                        case SXF_RAT_BIGTEXT:
228
0
                        {
229
0
                            if (bAddField)
230
0
                            {
231
0
                                OGRFieldDefn oField(oFieldName, OFTString);
232
0
                                oField.SetWidth(1024);
233
0
                                poFeatureDefn->AddFieldDefn(&oField);
234
0
                            }
235
0
                            GUInt32 scale2 = 0;
236
0
                            VSIFReadL(&scale2, sizeof(GUInt32), 1, fpSXF);
237
0
                            CPL_LSBPTR32(&scale2);
238
239
0
                            offset += scale2;
240
0
                            nCurrOff = scale2;
241
0
                            break;
242
0
                        }
243
0
                        default:
244
0
                            break;
245
0
                    }
246
0
                }
247
0
                if (nCurrOff == 0)
248
0
                    break;
249
0
                VSIFSeekL(fpSXF, nCurrOff, SEEK_CUR);
250
0
            }
251
0
        }
252
0
        return true;
253
0
    }
254
255
0
    return false;
256
0
}
257
258
/************************************************************************/
259
/*                           SetNextByIndex()                           */
260
/************************************************************************/
261
262
OGRErr OGRSXFLayer::SetNextByIndex(GIntBig nIndex)
263
0
{
264
0
    if (nIndex < 0 || nIndex > (long)mnRecordDesc.size())
265
0
        return OGRERR_FAILURE;
266
267
0
    oNextIt = mnRecordDesc.begin();
268
0
    std::advance(oNextIt, static_cast<size_t>(nIndex));
269
270
0
    return OGRERR_NONE;
271
0
}
272
273
/************************************************************************/
274
/*                             GetFeature()                             */
275
/************************************************************************/
276
277
OGRFeature *OGRSXFLayer::GetFeature(GIntBig nFID)
278
0
{
279
0
    const auto IT = mnRecordDesc.find(static_cast<long>(nFID));
280
0
    if (IT != mnRecordDesc.end())
281
0
    {
282
0
        VSIFSeekL(fpSXF, IT->second, SEEK_SET);
283
0
        OGRFeature *poFeature = GetNextRawFeature(IT->first);
284
0
        if (poFeature != nullptr && poFeature->GetGeometryRef() != nullptr &&
285
0
            GetSpatialRef() != nullptr)
286
0
        {
287
0
            poFeature->GetGeometryRef()->assignSpatialReference(
288
0
                GetSpatialRef());
289
0
        }
290
0
        return poFeature;
291
0
    }
292
293
0
    return nullptr;
294
0
}
295
296
/************************************************************************/
297
/*                           GetSpatialRef()                            */
298
/************************************************************************/
299
300
OGRSpatialReference *OGRSXFLayer::GetSpatialRef()
301
0
{
302
0
    return stSXFMapDescription.pSpatRef;
303
0
}
304
305
/************************************************************************/
306
/*                            IGetExtent()                              */
307
/************************************************************************/
308
309
OGRErr OGRSXFLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
310
                               bool bForce)
311
0
{
312
0
    if (bForce)
313
0
    {
314
0
        return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
315
0
    }
316
0
    else
317
0
    {
318
0
        psExtent->MinX = stSXFMapDescription.Env.MinX;
319
0
        psExtent->MaxX = stSXFMapDescription.Env.MaxX;
320
0
        psExtent->MinY = stSXFMapDescription.Env.MinY;
321
0
        psExtent->MaxY = stSXFMapDescription.Env.MaxY;
322
323
0
        return OGRERR_NONE;
324
0
    }
325
0
}
326
327
/************************************************************************/
328
/*                          GetFeatureCount()                           */
329
/************************************************************************/
330
331
GIntBig OGRSXFLayer::GetFeatureCount(int bForce)
332
0
{
333
0
    if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
334
0
        return static_cast<int>(mnRecordDesc.size());
335
0
    else
336
0
        return OGRLayer::GetFeatureCount(bForce);
337
0
}
338
339
/************************************************************************/
340
/*                            ResetReading()                            */
341
/************************************************************************/
342
343
void OGRSXFLayer::ResetReading()
344
345
0
{
346
0
    oNextIt = mnRecordDesc.begin();
347
0
}
348
349
/************************************************************************/
350
/*                           GetNextFeature()                           */
351
/************************************************************************/
352
353
OGRFeature *OGRSXFLayer::GetNextFeature()
354
0
{
355
0
    CPLMutexHolderD(m_hIOMutex);
356
0
    while (oNextIt != mnRecordDesc.end())
357
0
    {
358
0
        VSIFSeekL(fpSXF, oNextIt->second, SEEK_SET);
359
0
        OGRFeature *poFeature = GetNextRawFeature(oNextIt->first);
360
361
0
        ++oNextIt;
362
363
0
        if (poFeature == nullptr)
364
0
            continue;
365
366
0
        if ((m_poFilterGeom == nullptr ||
367
0
             FilterGeometry(poFeature->GetGeometryRef())) &&
368
0
            (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
369
0
        {
370
0
            if (poFeature->GetGeometryRef() != nullptr &&
371
0
                GetSpatialRef() != nullptr)
372
0
            {
373
0
                poFeature->GetGeometryRef()->assignSpatialReference(
374
0
                    GetSpatialRef());
375
0
            }
376
377
0
            return poFeature;
378
0
        }
379
380
0
        delete poFeature;
381
0
    }
382
0
    return nullptr;
383
0
}
384
385
/************************************************************************/
386
/*                           TestCapability()                           */
387
/************************************************************************/
388
389
int OGRSXFLayer::TestCapability(const char *pszCap)
390
391
0
{
392
0
    if (EQUAL(pszCap, OLCStringsAsUTF8) &&
393
0
        CPLCanRecode("test", "CP1251", CPL_ENC_UTF8) &&
394
0
        CPLCanRecode("test", "KOI8-R", CPL_ENC_UTF8))
395
0
        return TRUE;
396
0
    else if (EQUAL(pszCap, OLCRandomRead))
397
0
        return TRUE;
398
0
    else if (EQUAL(pszCap, OLCFastFeatureCount))
399
0
        return TRUE;
400
0
    else if (EQUAL(pszCap, OLCFastGetExtent))
401
0
        return TRUE;
402
0
    else if (EQUAL(pszCap, OLCFastSetNextByIndex))
403
0
        return TRUE;
404
0
    else if (EQUAL(pszCap, OLCZGeometries))
405
0
        return TRUE;
406
407
0
    return FALSE;
408
0
}
409
410
/************************************************************************/
411
/*                                TranslateXYH()                        */
412
/************************************************************************/
413
/****
414
 * TODO : Take into account information given in the passport
415
 * like unit of measurement, type and dimensions (integer, float, double) of
416
 * coordinate, the vector format, etc.
417
 */
418
419
GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription &certifInfo,
420
                                  const char *psBuff, GUInt32 nBufLen,
421
                                  double *dfX, double *dfY, double *dfH)
422
0
{
423
    // Xp, Yp(м) = Xo, Yo(м) + (Xd, Yd / R * S), (1)
424
425
0
    int offset = 0;
426
0
    switch (certifInfo.eValType)
427
0
    {
428
0
        case SXF_VT_SHORT:
429
0
        {
430
0
            if (nBufLen < 4)
431
0
                return 0;
432
0
            GInt16 x = 0;
433
0
            GInt16 y = 0;
434
0
            memcpy(&y, psBuff, 2);
435
0
            CPL_LSBPTR16(&y);
436
0
            memcpy(&x, psBuff + 2, 2);
437
0
            CPL_LSBPTR16(&x);
438
439
0
            if (stSXFMapDescription.bIsRealCoordinates)
440
0
            {
441
0
                *dfX = (double)x;
442
0
                *dfY = (double)y;
443
0
            }
444
0
            else
445
0
            {
446
0
                if (m_nSXFFormatVer == 3)
447
0
                {
448
0
                    *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
449
0
                    *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
450
0
                }
451
0
                else if (m_nSXFFormatVer == 4)
452
0
                {
453
                    // TODO: check on real data
454
0
                    *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
455
0
                    *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
456
0
                }
457
0
            }
458
459
0
            offset += 4;
460
461
0
            if (dfH != nullptr)
462
0
            {
463
0
                if (nBufLen < 4 + 4)
464
0
                    return 0;
465
0
                float h = 0.0f;
466
0
                memcpy(&h, psBuff + 4, 4);  // H always in float
467
0
                CPL_LSBPTR32(&h);
468
0
                *dfH = (double)h;
469
470
0
                offset += 4;
471
0
            }
472
0
        }
473
0
        break;
474
0
        case SXF_VT_FLOAT:
475
0
        {
476
0
            if (nBufLen < 8)
477
0
                return 0;
478
0
            float y = 0.0f;
479
0
            memcpy(&y, psBuff, 4);
480
0
            CPL_LSBPTR32(&y);
481
0
            float x = 0.0f;
482
0
            memcpy(&x, psBuff + 4, 4);
483
0
            CPL_LSBPTR32(&x);
484
485
0
            if (stSXFMapDescription.bIsRealCoordinates)
486
0
            {
487
0
                *dfX = (double)x;
488
0
                *dfY = (double)y;
489
0
            }
490
0
            else
491
0
            {
492
0
                *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
493
0
                *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
494
0
            }
495
496
0
            offset += 8;
497
498
0
            if (dfH != nullptr)
499
0
            {
500
0
                if (nBufLen < 8 + 4)
501
0
                    return 0;
502
0
                float h = 0.0f;
503
0
                memcpy(&h, psBuff + 8, 4);  // H always in float
504
0
                CPL_LSBPTR32(&h);
505
0
                *dfH = (double)h;
506
507
0
                offset += 4;
508
0
            }
509
0
        }
510
0
        break;
511
0
        case SXF_VT_INT:
512
0
        {
513
0
            if (nBufLen < 8)
514
0
                return 0;
515
0
            GInt32 x, y;
516
0
            memcpy(&y, psBuff, 4);
517
0
            CPL_LSBPTR32(&y);
518
0
            memcpy(&x, psBuff + 4, 4);
519
0
            CPL_LSBPTR32(&x);
520
521
0
            if (stSXFMapDescription.bIsRealCoordinates)
522
0
            {
523
0
                *dfX = (double)x;
524
0
                *dfY = (double)y;
525
0
            }
526
0
            else
527
0
            {
528
                // TODO: check on real data
529
0
                if (m_nSXFFormatVer == 3)
530
0
                {
531
0
                    *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
532
0
                    *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
533
0
                }
534
0
                else if (m_nSXFFormatVer == 4)
535
0
                {
536
0
                    *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
537
0
                    *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
538
0
                }
539
0
            }
540
0
            offset += 8;
541
542
0
            if (dfH != nullptr)
543
0
            {
544
0
                if (nBufLen < 8 + 4)
545
0
                    return 0;
546
0
                float h = 0.0f;
547
0
                memcpy(&h, psBuff + 8, 4);  // H always in float
548
0
                CPL_LSBPTR32(&h);
549
0
                *dfH = (double)h;
550
551
0
                offset += 4;
552
0
            }
553
0
        }
554
0
        break;
555
0
        case SXF_VT_DOUBLE:
556
0
        {
557
0
            if (nBufLen < 16)
558
0
                return 0;
559
0
            double x = 0.0;
560
0
            double y = 0.0;
561
0
            memcpy(&y, psBuff, 8);
562
0
            CPL_LSBPTR64(&y);
563
0
            memcpy(&x, psBuff + 8, 8);
564
0
            CPL_LSBPTR64(&x);
565
566
0
            if (stSXFMapDescription.bIsRealCoordinates)
567
0
            {
568
0
                *dfX = x;
569
0
                *dfY = y;
570
0
            }
571
0
            else
572
0
            {
573
0
                *dfX = stSXFMapDescription.dfXOr + x * m_dfCoeff;
574
0
                *dfY = stSXFMapDescription.dfYOr + y * m_dfCoeff;
575
0
            }
576
577
0
            offset += 16;
578
579
0
            if (dfH != nullptr)
580
0
            {
581
0
                if (nBufLen < 16 + 8)
582
0
                    return 0;
583
0
                double h = 0.0;
584
0
                memcpy(&h, psBuff + 16, 8);  // H in double
585
0
                CPL_LSBPTR64(&h);
586
0
                *dfH = (double)h;
587
588
0
                offset += 8;
589
0
            }
590
0
        }
591
0
        break;
592
0
    };
593
594
0
    return offset;
595
0
}
596
597
/************************************************************************/
598
/*                         GetNextRawFeature()                          */
599
/************************************************************************/
600
601
OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
602
0
{
603
0
    SXFRecordHeader stRecordHeader;
604
0
    int nObjectRead = static_cast<int>(
605
0
        VSIFReadL(&stRecordHeader, sizeof(SXFRecordHeader), 1, fpSXF));
606
607
0
    if (nObjectRead != 1)
608
0
    {
609
0
        CPLError(CE_Failure, CPLE_FileIO, "SXF. Read record failed.");
610
0
        return nullptr;
611
0
    }
612
0
    CPL_LSBPTR32(&(stRecordHeader.nID));
613
0
    if (stRecordHeader.nID != IDSXFOBJ)
614
0
    {
615
0
        CPLError(CE_Failure, CPLE_FileIO, "SXF. Read record failed.");
616
0
        return nullptr;
617
0
    }
618
0
    CPL_LSBPTR32(&(stRecordHeader.nFullLength));
619
0
    CPL_LSBPTR32(&(stRecordHeader.nGeometryLength));
620
0
    CPL_LSBPTR32(&(stRecordHeader.nClassifyCode));
621
0
    CPL_LSBPTR16(&(stRecordHeader.anGroup[0]));
622
0
    CPL_LSBPTR16(&(stRecordHeader.anGroup[1]));
623
0
    CPL_LSBPTR32(&(stRecordHeader.nPointCount));
624
0
    CPL_LSBPTR16(&(stRecordHeader.nSubObjectCount));
625
0
    CPL_LSBPTR16(&(stRecordHeader.nPointCountSmall));
626
627
0
    SXFGeometryType eGeomType = SXF_GT_Unknown;
628
0
    GByte code = 0;
629
630
0
    if (m_nSXFFormatVer == 3)
631
0
    {
632
0
        if (CHECK_BIT(stRecordHeader.nRef[2], 3))
633
0
        {
634
0
            if (CHECK_BIT(stRecordHeader.nRef[2], 4))
635
0
            {
636
0
                code = 0x22;
637
0
                stRecordHeader.nSubObjectCount = 0;
638
0
            }
639
0
            else
640
0
            {
641
0
                code = 0x21;
642
0
                stRecordHeader.nSubObjectCount = 0;
643
0
            }
644
0
        }
645
0
        else
646
0
        {
647
0
            code = stRecordHeader.nRef[0] & 3;  // get first 2 bits
648
0
        }
649
0
    }
650
0
    else if (m_nSXFFormatVer == 4)
651
0
    {
652
0
        if (CHECK_BIT(stRecordHeader.nRef[2], 5))
653
0
        {
654
0
            stRecordHeader.nSubObjectCount = 0;
655
0
        }
656
657
        // check if vector
658
0
        code = stRecordHeader.nRef[0] & 15;  // get first 4 bits
659
0
        if (code == 0x04)                    // xxxx0100
660
0
        {
661
0
            code = 0x21;
662
0
            stRecordHeader.nSubObjectCount = 0;
663
            // if (CHECK_BIT(stRecordHeader.nRef[2], 5))
664
            //{
665
            //     code = 0x22;
666
            //     stRecordHeader.nSubObjectCount = 0;
667
            // }
668
            // else
669
            //{
670
            //     code = 0x21;
671
            //     stRecordHeader.nSubObjectCount = 0;
672
            // }
673
            // if (CHECK_BIT(stRecordHeader.nRef[2], 4))
674
            //{
675
            // }
676
            // else
677
            //{
678
            // }
679
0
        }
680
0
    }
681
682
0
    if (code == 0x00)  // xxxx0000
683
0
        eGeomType = SXF_GT_Line;
684
0
    else if (code == 0x01)  // xxxx0001
685
0
        eGeomType = SXF_GT_Polygon;
686
0
    else if (code == 0x02)  // xxxx0010
687
0
        eGeomType = SXF_GT_Point;
688
0
    else if (code == 0x03)  // xxxx0011
689
0
        eGeomType = SXF_GT_Text;
690
#ifdef not_possible_given_above_code /* see below code too if re-enabling this \
691
                                      */
692
    // beginning 4.0
693
    else if (code == 0x04)  // xxxx0100
694
    {
695
        CPLError(CE_Warning, CPLE_NotSupported, "SXF. Not support type.");
696
        eGeomType = SXF_GT_Vector;
697
    }
698
#endif
699
0
    else if (code == 0x05)  // xxxx0101
700
0
        eGeomType = SXF_GT_TextTemplate;
701
0
    else if (code == 0x21)
702
0
        eGeomType = SXF_GT_VectorAngle;
703
0
    else if (code == 0x22)
704
0
        eGeomType = SXF_GT_VectorScaled;
705
706
0
    bool bHasAttributes = CHECK_BIT(stRecordHeader.nRef[1], 1);
707
0
    bool bHasRefVector = CHECK_BIT(stRecordHeader.nRef[1], 3);
708
0
    if (bHasRefVector == true)
709
0
        CPLError(CE_Failure, CPLE_NotSupported,
710
0
                 "SXF. Parsing the vector of the tying not support.");
711
712
0
    SXFRecordDescription stCertInfo;
713
0
    if (stRecordHeader.nPointCountSmall == 65535)
714
0
    {
715
0
        stCertInfo.nPointCount = stRecordHeader.nPointCount;
716
0
    }
717
0
    else
718
0
    {
719
0
        stCertInfo.nPointCount = stRecordHeader.nPointCountSmall;
720
0
    }
721
0
    stCertInfo.nSubObjectCount = stRecordHeader.nSubObjectCount;
722
723
0
    bool bFloatType(false), bBigType(false);
724
0
    bool b3D(true);
725
0
    if (m_nSXFFormatVer == 3)
726
0
    {
727
0
        b3D = CHECK_BIT(stRecordHeader.nRef[2], 1);
728
0
        bFloatType = CHECK_BIT(stRecordHeader.nRef[2], 2);
729
0
        bBigType = CHECK_BIT(stRecordHeader.nRef[1], 2);
730
0
        stCertInfo.bHasTextSign = CHECK_BIT(stRecordHeader.nRef[2], 5);
731
0
    }
732
0
    else if (m_nSXFFormatVer == 4)
733
0
    {
734
0
        b3D = CHECK_BIT(stRecordHeader.nRef[2], 1);
735
0
        bFloatType = CHECK_BIT(stRecordHeader.nRef[2], 2);
736
0
        bBigType = CHECK_BIT(stRecordHeader.nRef[1], 2);
737
0
        stCertInfo.bHasTextSign = CHECK_BIT(stRecordHeader.nRef[2], 3);
738
0
    }
739
    // Else trouble.
740
741
0
    if (b3D)  // xxxxxx1x
742
0
        stCertInfo.bDim = 1;
743
0
    else
744
0
        stCertInfo.bDim = 0;
745
746
0
    if (bFloatType)
747
0
    {
748
0
        if (bBigType)
749
0
        {
750
0
            stCertInfo.eValType = SXF_VT_DOUBLE;
751
0
        }
752
0
        else
753
0
        {
754
0
            stCertInfo.eValType = SXF_VT_FLOAT;
755
0
        }
756
0
    }
757
0
    else
758
0
    {
759
0
        if (bBigType)
760
0
        {
761
0
            stCertInfo.eValType = SXF_VT_INT;
762
0
        }
763
0
        else
764
0
        {
765
0
            stCertInfo.eValType = SXF_VT_SHORT;
766
0
        }
767
0
    }
768
769
0
    stCertInfo.bFormat = CHECK_BIT(stRecordHeader.nRef[2], 0);
770
0
    stCertInfo.eGeomType = eGeomType;
771
772
0
    OGRFeature *poFeature = nullptr;
773
0
    if (stRecordHeader.nGeometryLength > 100 * 1024 * 1024)
774
0
        return nullptr;
775
0
    char *recordCertifBuf =
776
0
        (char *)VSI_MALLOC_VERBOSE(stRecordHeader.nGeometryLength);
777
0
    if (recordCertifBuf == nullptr)
778
0
        return nullptr;
779
0
    nObjectRead = static_cast<int>(
780
0
        VSIFReadL(recordCertifBuf, stRecordHeader.nGeometryLength, 1, fpSXF));
781
0
    if (nObjectRead != 1)
782
0
    {
783
0
        CPLError(CE_Failure, CPLE_FileIO, "SXF. Read geometry failed.");
784
0
        CPLFree(recordCertifBuf);
785
0
        return nullptr;
786
0
    }
787
788
0
    if (eGeomType == SXF_GT_Point)
789
0
        poFeature = TranslatePoint(stCertInfo, recordCertifBuf,
790
0
                                   stRecordHeader.nGeometryLength);
791
0
    else if (eGeomType == SXF_GT_Line || eGeomType == SXF_GT_VectorScaled)
792
0
        poFeature = TranslateLine(stCertInfo, recordCertifBuf,
793
0
                                  stRecordHeader.nGeometryLength);
794
0
    else if (eGeomType == SXF_GT_Polygon)
795
0
        poFeature = TranslatePolygon(stCertInfo, recordCertifBuf,
796
0
                                     stRecordHeader.nGeometryLength);
797
0
    else if (eGeomType == SXF_GT_Text)
798
0
        poFeature = TranslateText(stCertInfo, recordCertifBuf,
799
0
                                  stRecordHeader.nGeometryLength);
800
0
    else if (eGeomType == SXF_GT_VectorAngle)
801
0
    {
802
0
        poFeature = TranslateVetorAngle(stCertInfo, recordCertifBuf,
803
0
                                        stRecordHeader.nGeometryLength);
804
0
    }
805
#ifdef not_possible_given_above_code
806
    else if (eGeomType == SXF_GT_Vector)
807
    {
808
        CPLError(CE_Warning, CPLE_NotSupported,
809
                 "SXF. Geometry type Vector do not support.");
810
        CPLFree(recordCertifBuf);
811
        return NULL;
812
    }
813
#endif
814
0
    else if (eGeomType == SXF_GT_TextTemplate)  // TODO realize this
815
0
    {
816
0
        CPLError(CE_Warning, CPLE_NotSupported,
817
0
                 "SXF. Geometry type Text Template do not support.");
818
0
        CPLFree(recordCertifBuf);
819
0
        return nullptr;
820
0
    }
821
0
    else
822
0
    {
823
0
        CPLError(CE_Failure, CPLE_NotSupported,
824
0
                 "SXF. Unsupported geometry type.");
825
0
        CPLFree(recordCertifBuf);
826
0
        return nullptr;
827
0
    }
828
829
0
    if (poFeature == nullptr)
830
0
    {
831
0
        CPLFree(recordCertifBuf);
832
0
        return nullptr;
833
0
    }
834
835
0
    poFeature->SetField(sFIDColumn_, (int)nFID);
836
837
0
    poFeature->SetField("CLCODE", (int)stRecordHeader.nClassifyCode);
838
839
0
    CPLString szName = mnClassificators[stRecordHeader.nClassifyCode];
840
841
0
    if (szName.empty())
842
0
    {
843
0
        szName.Printf("%d", stRecordHeader.nClassifyCode);
844
0
    }
845
0
    poFeature->SetField("CLNAME", szName);
846
847
0
    poFeature->SetField("OBJECTNUMB", stRecordHeader.nSubObjectCount);
848
849
0
    if (bHasAttributes)
850
0
    {
851
0
        if (stRecordHeader.nFullLength < 32 ||
852
0
            stRecordHeader.nGeometryLength > stRecordHeader.nFullLength - 32)
853
0
        {
854
0
            CPLFree(recordCertifBuf);
855
0
            delete poFeature;
856
0
            return nullptr;
857
0
        }
858
0
        size_t nSemanticsSize =
859
0
            stRecordHeader.nFullLength - 32 - stRecordHeader.nGeometryLength;
860
0
        if (nSemanticsSize > 1024 * 1024)
861
0
        {
862
0
            CPLFree(recordCertifBuf);
863
0
            delete poFeature;
864
0
            return nullptr;
865
0
        }
866
0
        char *psSemanticsdBuf = (char *)VSI_MALLOC_VERBOSE(nSemanticsSize);
867
0
        if (psSemanticsdBuf == nullptr)
868
0
        {
869
0
            CPLFree(recordCertifBuf);
870
0
            delete poFeature;
871
0
            return nullptr;
872
0
        }
873
0
        char *psSemanticsdBufOrig = psSemanticsdBuf;
874
0
        nObjectRead = static_cast<int>(
875
0
            VSIFReadL(psSemanticsdBuf, nSemanticsSize, 1, fpSXF));
876
0
        if (nObjectRead == 1)
877
0
        {
878
0
            size_t offset = 0;
879
0
            double nVal = 0;
880
881
0
            while (offset + sizeof(SXFRecordAttributeInfo) < nSemanticsSize)
882
0
            {
883
0
                char *psSemanticsdBufBeg = psSemanticsdBuf + offset;
884
0
                SXFRecordAttributeInfo stAttInfo =
885
0
                    *reinterpret_cast<SXFRecordAttributeInfo *>(
886
0
                        psSemanticsdBufBeg);
887
0
                CPL_LSBPTR16(&(stAttInfo.nCode));
888
0
                offset += 4;
889
890
0
                CPLString oFieldName;
891
0
                oFieldName.Printf("SC_%d", stAttInfo.nCode);
892
893
0
                CPLString oFieldValue;
894
895
0
                SXFRecordAttributeType eType =
896
0
                    (SXFRecordAttributeType)stAttInfo.nType;
897
898
0
                switch (eType)
899
0
                {
900
0
                    case SXF_RAT_ASCIIZ_DOS:
901
0
                    {
902
0
                        unsigned nLen = unsigned(stAttInfo.nScale) + 1;
903
0
                        if (nLen > nSemanticsSize ||
904
0
                            nSemanticsSize - nLen < offset)
905
0
                        {
906
0
                            nSemanticsSize = 0;
907
0
                            break;
908
0
                        }
909
0
                        char *value = (char *)CPLMalloc(nLen);
910
0
                        memcpy(value, psSemanticsdBuf + offset, nLen);
911
0
                        value[nLen - 1] = 0;
912
0
                        char *pszRecoded =
913
0
                            CPLRecode(value, "CP866", CPL_ENC_UTF8);
914
0
                        poFeature->SetField(oFieldName, pszRecoded);
915
0
                        CPLFree(pszRecoded);
916
0
                        CPLFree(value);
917
918
0
                        offset += stAttInfo.nScale + 1;
919
0
                        break;
920
0
                    }
921
0
                    case SXF_RAT_ONEBYTE:
922
0
                    {
923
0
                        if (offset + sizeof(GByte) > nSemanticsSize)
924
0
                        {
925
0
                            nSemanticsSize = 0;
926
0
                            break;
927
0
                        }
928
0
                        GByte nTmpVal = 0;
929
0
                        memcpy(&nTmpVal, psSemanticsdBuf + offset,
930
0
                               sizeof(GByte));
931
0
                        nVal = double(nTmpVal) *
932
0
                               pow(10.0, (double)stAttInfo.nScale);
933
934
0
                        poFeature->SetField(oFieldName, nVal);
935
0
                        offset += 1;
936
0
                        break;
937
0
                    }
938
0
                    case SXF_RAT_TWOBYTE:
939
0
                    {
940
0
                        if (offset + sizeof(GInt16) > nSemanticsSize)
941
0
                        {
942
0
                            nSemanticsSize = 0;
943
0
                            break;
944
0
                        }
945
0
                        GInt16 nTmpVal = 0;
946
0
                        memcpy(&nTmpVal, psSemanticsdBuf + offset,
947
0
                               sizeof(GInt16));
948
0
                        nVal = double(CPL_LSBWORD16(nTmpVal)) *
949
0
                               pow(10.0, (double)stAttInfo.nScale);
950
951
0
                        poFeature->SetField(oFieldName, nVal);
952
0
                        offset += 2;
953
0
                        break;
954
0
                    }
955
0
                    case SXF_RAT_FOURBYTE:
956
0
                    {
957
0
                        if (offset + sizeof(GInt32) > nSemanticsSize)
958
0
                        {
959
0
                            nSemanticsSize = 0;
960
0
                            break;
961
0
                        }
962
0
                        GInt32 nTmpVal = 0;
963
0
                        memcpy(&nTmpVal, psSemanticsdBuf + offset,
964
0
                               sizeof(GInt32));
965
0
                        nVal = double(CPL_LSBWORD32(nTmpVal)) *
966
0
                               pow(10.0, (double)stAttInfo.nScale);
967
968
0
                        poFeature->SetField(oFieldName, nVal);
969
0
                        offset += 4;
970
0
                        break;
971
0
                    }
972
0
                    case SXF_RAT_EIGHTBYTE:
973
0
                    {
974
0
                        if (offset + sizeof(double) > nSemanticsSize)
975
0
                        {
976
0
                            nSemanticsSize = 0;
977
0
                            break;
978
0
                        }
979
0
                        double dfTmpVal = 0.0;
980
0
                        memcpy(&dfTmpVal, psSemanticsdBuf + offset,
981
0
                               sizeof(double));
982
0
                        CPL_LSBPTR64(&dfTmpVal);
983
0
                        const double d =
984
0
                            dfTmpVal * pow(10.0, (double)stAttInfo.nScale);
985
986
0
                        poFeature->SetField(oFieldName, d);
987
988
0
                        offset += 8;
989
0
                        break;
990
0
                    }
991
0
                    case SXF_RAT_ANSI_WIN:
992
0
                    {
993
0
                        unsigned nLen = unsigned(stAttInfo.nScale) + 1;
994
0
                        if (nLen > nSemanticsSize ||
995
0
                            nSemanticsSize - nLen < offset)
996
0
                        {
997
0
                            nSemanticsSize = 0;
998
0
                            break;
999
0
                        }
1000
0
                        char *value = (char *)CPLMalloc(nLen);
1001
0
                        memcpy(value, psSemanticsdBuf + offset, nLen);
1002
0
                        value[nLen - 1] = 0;
1003
0
                        char *pszRecoded =
1004
0
                            CPLRecode(value, "CP1251", CPL_ENC_UTF8);
1005
0
                        poFeature->SetField(oFieldName, pszRecoded);
1006
0
                        CPLFree(pszRecoded);
1007
0
                        CPLFree(value);
1008
1009
0
                        offset += nLen;
1010
0
                        break;
1011
0
                    }
1012
0
                    case SXF_RAT_UNICODE:
1013
0
                    {
1014
0
                        uint64_t nLen64 =
1015
0
                            (static_cast<uint64_t>(stAttInfo.nScale) + 1) * 2;
1016
0
                        unsigned nLen = static_cast<unsigned>(nLen64);
1017
0
                        if (/* nLen < 2 || */ nLen64 > nSemanticsSize ||
1018
0
                            nSemanticsSize - nLen < offset)
1019
0
                        {
1020
0
                            nSemanticsSize = 0;
1021
0
                            break;
1022
0
                        }
1023
0
                        char *value = (char *)CPLMalloc(nLen);
1024
0
                        memcpy(value, psSemanticsdBuf + offset, nLen - 2);
1025
0
                        value[nLen - 1] = 0;
1026
0
                        value[nLen - 2] = 0;
1027
0
                        char *dst = (char *)CPLMalloc(nLen);
1028
0
                        int nCount = 0;
1029
0
                        for (int i = 0; (unsigned)i < nLen; i += 2)
1030
0
                        {
1031
0
                            unsigned char ucs = value[i];
1032
1033
0
                            if (ucs < 0x80U)
1034
0
                            {
1035
0
                                dst[nCount++] = ucs;
1036
0
                            }
1037
0
                            else
1038
0
                            {
1039
0
                                dst[nCount++] = 0xc0 | (ucs >> 6);
1040
0
                                dst[nCount++] = 0x80 | (ucs & 0x3F);
1041
0
                            }
1042
0
                        }
1043
1044
0
                        poFeature->SetField(oFieldName, dst);
1045
0
                        CPLFree(dst);
1046
0
                        CPLFree(value);
1047
1048
0
                        offset += nLen;
1049
0
                        break;
1050
0
                    }
1051
0
                    case SXF_RAT_BIGTEXT:
1052
0
                    {
1053
0
                        if (offset + sizeof(GUInt32) > nSemanticsSize)
1054
0
                        {
1055
0
                            nSemanticsSize = 0;
1056
0
                            break;
1057
0
                        }
1058
0
                        GUInt32 scale2 = 0;
1059
0
                        memcpy(&scale2, psSemanticsdBuf + offset,
1060
0
                               sizeof(GUInt32));
1061
0
                        CPL_LSBPTR32(&scale2);
1062
                        /* FIXME add ?: offset += sizeof(GUInt32); */
1063
0
                        if (scale2 > nSemanticsSize - 1 ||
1064
0
                            nSemanticsSize - (scale2 + 1) < offset)
1065
0
                        {
1066
0
                            nSemanticsSize = 0;
1067
0
                            break;
1068
0
                        }
1069
1070
0
                        char *value = (char *)CPLMalloc(scale2 + 1);
1071
0
                        memcpy(value, psSemanticsdBuf + offset, scale2 + 1);
1072
0
                        value[scale2] = 0;
1073
0
                        char *pszRecoded =
1074
0
                            CPLRecode(value, CPL_ENC_UTF16, CPL_ENC_UTF8);
1075
0
                        poFeature->SetField(oFieldName, pszRecoded);
1076
0
                        CPLFree(pszRecoded);
1077
0
                        CPLFree(value);
1078
1079
0
                        offset += scale2;
1080
0
                        break;
1081
0
                    }
1082
0
                    default:
1083
0
                        CPLFree(recordCertifBuf);
1084
0
                        CPLFree(psSemanticsdBufOrig);
1085
0
                        delete poFeature;
1086
0
                        return nullptr;
1087
0
                }
1088
0
            }
1089
0
        }
1090
0
        CPLFree(psSemanticsdBufOrig);
1091
0
    }
1092
1093
0
    poFeature->SetFID(nFID);
1094
1095
0
    CPLFree(recordCertifBuf);
1096
1097
0
    return poFeature;
1098
0
}
1099
1100
/************************************************************************/
1101
/*                         TranslatePoint   ()                          */
1102
/************************************************************************/
1103
1104
OGRFeature *OGRSXFLayer::TranslatePoint(const SXFRecordDescription &certifInfo,
1105
                                        const char *psRecordBuf,
1106
                                        GUInt32 nBufLen)
1107
0
{
1108
0
    double dfX = 1.0;
1109
0
    double dfY = 1.0;
1110
0
    double dfZ = 0.0;
1111
0
    GUInt32 nOffset = 0;
1112
0
    GUInt32 nDelta = 0;
1113
1114
0
    if (certifInfo.bDim == 1)
1115
0
    {
1116
0
        nDelta =
1117
0
            TranslateXYH(certifInfo, psRecordBuf, nBufLen, &dfX, &dfY, &dfZ);
1118
0
    }
1119
0
    else
1120
0
    {
1121
0
        nDelta = TranslateXYH(certifInfo, psRecordBuf, nBufLen, &dfX, &dfY);
1122
0
    }
1123
1124
0
    if (nDelta == 0)
1125
0
        return nullptr;
1126
0
    nOffset += nDelta;
1127
1128
    // OGRFeatureDefn *fd = poFeatureDefn->Clone();
1129
    // fd->SetGeomType( wkbMultiPoint );
1130
    //   OGRFeature *poFeature = new OGRFeature(fd);
1131
0
    OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
1132
0
    OGRMultiPoint *poMPt = new OGRMultiPoint();
1133
1134
0
    poMPt->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
1135
1136
    /*---------------------- Reading SubObjects
1137
     * --------------------------------*/
1138
1139
0
    for (int count = 0; count < certifInfo.nSubObjectCount; count++)
1140
0
    {
1141
0
        if (nOffset + 4 > nBufLen)
1142
0
            break;
1143
1144
0
        GUInt16 nSubObj = 0;
1145
0
        memcpy(&nSubObj, psRecordBuf + nOffset, 2);
1146
0
        CPL_LSBPTR16(&nSubObj);
1147
1148
0
        GUInt16 nCoords = 0;
1149
0
        memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
1150
0
        CPL_LSBPTR16(&nCoords);
1151
1152
0
        nOffset += 4;
1153
1154
0
        for (int i = 0; i < nCoords; i++)
1155
0
        {
1156
0
            const char *psCoords = psRecordBuf + nOffset;
1157
1158
0
            if (certifInfo.bDim == 1)
1159
0
            {
1160
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1161
0
                                      &dfX, &dfY, &dfZ);
1162
0
            }
1163
0
            else
1164
0
            {
1165
0
                dfZ = 0.0;
1166
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1167
0
                                      &dfX, &dfY);
1168
0
            }
1169
1170
0
            if (nDelta == 0)
1171
0
                break;
1172
0
            nOffset += nDelta;
1173
1174
0
            poMPt->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
1175
0
        }
1176
0
    }
1177
1178
    /*****
1179
     * TODO :
1180
     *          - Translate graphics
1181
     *          - Translate 3D vector
1182
     */
1183
1184
0
    poFeature->SetGeometryDirectly(poMPt);
1185
1186
0
    return poFeature;
1187
0
}
1188
1189
/************************************************************************/
1190
/*                         TranslateLine    ()                          */
1191
/************************************************************************/
1192
1193
OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription &certifInfo,
1194
                                       const char *psRecordBuf, GUInt32 nBufLen)
1195
0
{
1196
0
    double dfX = 1.0;
1197
0
    double dfY = 1.0;
1198
0
    double dfZ = 0.0;
1199
0
    GUInt32 nOffset = 0;
1200
1201
    // OGRFeatureDefn *fd = poFeatureDefn->Clone();
1202
    // fd->SetGeomType( wkbMultiLineString );
1203
    //   OGRFeature *poFeature = new OGRFeature(fd);
1204
1205
0
    OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
1206
0
    OGRMultiLineString *poMLS = new OGRMultiLineString();
1207
1208
    /*---------------------- Reading Primary Line
1209
     * --------------------------------*/
1210
1211
0
    OGRLineString *poLS = new OGRLineString();
1212
1213
0
    for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
1214
0
    {
1215
0
        const char *psCoords = psRecordBuf + nOffset;
1216
1217
0
        GInt32 nDelta;
1218
0
        if (certifInfo.bDim == 1)
1219
0
        {
1220
0
            nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
1221
0
                                  &dfY, &dfZ);
1222
0
        }
1223
0
        else
1224
0
        {
1225
0
            dfZ = 0.0;
1226
0
            nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
1227
0
                                  &dfY);
1228
0
        }
1229
1230
0
        if (nDelta == 0)
1231
0
            break;
1232
0
        nOffset += nDelta;
1233
1234
0
        poLS->addPoint(dfX, dfY, dfZ);
1235
0
    }
1236
1237
0
    poMLS->addGeometry(poLS);
1238
1239
    /*---------------------- Reading Sub Lines
1240
     * --------------------------------*/
1241
1242
0
    for (GUInt16 count = 0; count < certifInfo.nSubObjectCount; count++)
1243
0
    {
1244
0
        poLS->empty();
1245
1246
0
        if (nOffset + 4 > nBufLen)
1247
0
            break;
1248
1249
0
        GUInt16 nSubObj = 0;
1250
0
        memcpy(&nSubObj, psRecordBuf + nOffset, 2);
1251
0
        CPL_LSBPTR16(&nSubObj);
1252
1253
0
        GUInt16 nCoords = 0;
1254
0
        memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
1255
0
        CPL_LSBPTR16(&nCoords);
1256
1257
0
        nOffset += 4;
1258
1259
0
        for (GUInt16 i = 0; i < nCoords; i++)
1260
0
        {
1261
0
            const char *psCoords = psRecordBuf + nOffset;
1262
0
            GInt32 nDelta;
1263
0
            if (certifInfo.bDim == 1)
1264
0
            {
1265
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1266
0
                                      &dfX, &dfY, &dfZ);
1267
0
            }
1268
0
            else
1269
0
            {
1270
0
                dfZ = 0.0;
1271
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1272
0
                                      &dfX, &dfY);
1273
0
            }
1274
1275
0
            if (nDelta == 0)
1276
0
                break;
1277
0
            nOffset += nDelta;
1278
1279
0
            poLS->addPoint(dfX, dfY, dfZ);
1280
0
        }
1281
1282
0
        poMLS->addGeometry(poLS);
1283
0
    }  // for
1284
1285
0
    delete poLS;
1286
0
    poFeature->SetGeometryDirectly(poMLS);
1287
1288
    /*****
1289
     * TODO :
1290
     *          - Translate graphics
1291
     *          - Translate 3D vector
1292
     */
1293
1294
0
    return poFeature;
1295
0
}
1296
1297
/************************************************************************/
1298
/*                       TranslateVetorAngle()                          */
1299
/************************************************************************/
1300
1301
OGRFeature *
1302
OGRSXFLayer::TranslateVetorAngle(const SXFRecordDescription &certifInfo,
1303
                                 const char *psRecordBuf, GUInt32 nBufLen)
1304
0
{
1305
0
    if (certifInfo.nPointCount != 2)
1306
0
    {
1307
0
        CPLError(CE_Failure, CPLE_NotSupported,
1308
0
                 "SXF. The vector object should have 2 points, but not.");
1309
0
        return nullptr;
1310
0
    }
1311
1312
0
    GUInt32 nOffset = 0;
1313
1314
0
    OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
1315
0
    OGRPoint *poPT = new OGRPoint();
1316
1317
    /*---------------------- Reading Primary Line
1318
     * --------------------------------*/
1319
1320
0
    OGRLineString *poLS = new OGRLineString();
1321
1322
0
    for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
1323
0
    {
1324
0
        const char *psCoords = psRecordBuf + nOffset;
1325
1326
0
        double dfX = 1.0;
1327
0
        double dfY = 1.0;
1328
0
        double dfZ = 0.0;
1329
0
        GInt32 nDelta;
1330
0
        if (certifInfo.bDim == 1)
1331
0
        {
1332
0
            nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
1333
0
                                  &dfY, &dfZ);
1334
0
        }
1335
0
        else
1336
0
        {
1337
0
            dfZ = 0.0;
1338
0
            nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
1339
0
                                  &dfY);
1340
0
        }
1341
0
        if (nDelta == 0)
1342
0
            break;
1343
0
        nOffset += nDelta;
1344
1345
0
        poLS->addPoint(dfX, dfY, dfZ);
1346
0
    }
1347
1348
0
    poLS->StartPoint(poPT);
1349
1350
0
    OGRPoint *poAngPT = new OGRPoint();
1351
0
    poLS->EndPoint(poAngPT);
1352
1353
0
    const double xDiff = poPT->getX() - poAngPT->getX();
1354
0
    const double yDiff = poPT->getY() - poAngPT->getY();
1355
0
    double dfAngle = atan2(xDiff, yDiff) * TO_DEGREES - 90;
1356
0
    if (dfAngle < 0)
1357
0
        dfAngle += 360;
1358
1359
0
    poFeature->SetGeometryDirectly(poPT);
1360
0
    poFeature->SetField("ANGLE", dfAngle);
1361
1362
0
    delete poAngPT;
1363
0
    delete poLS;
1364
1365
0
    return poFeature;
1366
0
}
1367
1368
/************************************************************************/
1369
/*                         TranslatePolygon ()                          */
1370
/************************************************************************/
1371
1372
OGRFeature *
1373
OGRSXFLayer::TranslatePolygon(const SXFRecordDescription &certifInfo,
1374
                              const char *psRecordBuf, GUInt32 nBufLen)
1375
0
{
1376
0
    double dfX = 1.0;
1377
0
    double dfY = 1.0;
1378
0
    double dfZ = 0.0;
1379
0
    GUInt32 nOffset = 0;
1380
0
    GUInt32 nDelta = 0;
1381
1382
0
    OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
1383
0
    OGRPolygon *poPoly = new OGRPolygon();
1384
0
    OGRLineString *poLS = new OGRLineString();
1385
1386
    /*---------------------- Reading Primary Polygon
1387
     * --------------------------------*/
1388
0
    for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
1389
0
    {
1390
0
        const char *psBuf = psRecordBuf + nOffset;
1391
0
        if (certifInfo.bDim == 1)
1392
0
        {
1393
0
            nDelta = TranslateXYH(certifInfo, psBuf, nBufLen - nOffset, &dfX,
1394
0
                                  &dfY, &dfZ);
1395
0
        }
1396
0
        else
1397
0
        {
1398
0
            dfZ = 0.0;
1399
0
            nDelta =
1400
0
                TranslateXYH(certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY);
1401
0
        }
1402
1403
0
        if (nDelta == 0)
1404
0
            break;
1405
0
        nOffset += nDelta;
1406
0
        poLS->addPoint(dfX, dfY, dfZ);
1407
0
    }  // for
1408
1409
0
    OGRLinearRing *poLR = new OGRLinearRing();
1410
0
    poLR->addSubLineString(poLS, 0);
1411
1412
0
    poPoly->addRingDirectly(poLR);
1413
1414
    /*---------------------- Reading Sub Lines
1415
     * --------------------------------*/
1416
1417
0
    for (int count = 0; count < certifInfo.nSubObjectCount; count++)
1418
0
    {
1419
0
        poLS->empty();
1420
1421
0
        if (nOffset + 4 > nBufLen)
1422
0
            break;
1423
1424
0
        GUInt16 nSubObj = 0;
1425
0
        memcpy(&nSubObj, psRecordBuf + nOffset, 2);
1426
0
        CPL_LSBPTR16(&nSubObj);
1427
1428
0
        GUInt16 nCoords = 0;
1429
0
        memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
1430
0
        CPL_LSBPTR16(&nCoords);
1431
1432
        // TODO: Is this really what the buffer size should be?
1433
0
        if (nCoords * nDelta != nBufLen - nOffset + 2 - 6)
1434
0
        {
1435
0
            CPLError(CE_Warning, CPLE_FileIO,
1436
0
                     "SXF raw feature size incorrect.  "
1437
0
                     "%d %d",
1438
0
                     nCoords * nDelta, nBufLen - nOffset + 2 - 6);
1439
            // TODO: How best to gracefully exit and report an issue?
1440
            // break; or cleanup and return NULL?
1441
0
        }
1442
1443
0
        nOffset += 4;
1444
1445
0
        for (int i = 0; i < nCoords; i++)
1446
0
        {
1447
0
            const char *psCoords = psRecordBuf + nOffset;
1448
0
            if (certifInfo.bDim == 1)
1449
0
            {
1450
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1451
0
                                      &dfX, &dfY, &dfZ);
1452
0
            }
1453
0
            else
1454
0
            {
1455
0
                dfZ = 0.0;
1456
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1457
0
                                      &dfX, &dfY);
1458
0
            }
1459
1460
0
            if (nDelta == 0)
1461
0
                break;
1462
0
            nOffset += nDelta;
1463
1464
0
            poLS->addPoint(dfX, dfY, dfZ);
1465
0
        }
1466
1467
0
        poLR = new OGRLinearRing();
1468
0
        poLR->addSubLineString(poLS, 0);
1469
1470
0
        poPoly->addRingDirectly(poLR);
1471
0
    }  // for
1472
1473
0
    poFeature->SetGeometryDirectly(poPoly);  // poLS);
1474
0
    delete poLS;
1475
1476
    /*****
1477
     * TODO :
1478
     *          - Translate graphics
1479
     *          - Translate 3D vector
1480
     */
1481
0
    return poFeature;
1482
0
}
1483
1484
/************************************************************************/
1485
/*                         TranslateText    ()                          */
1486
/************************************************************************/
1487
OGRFeature *OGRSXFLayer::TranslateText(const SXFRecordDescription &certifInfo,
1488
                                       const char *psRecordBuf, GUInt32 nBufLen)
1489
0
{
1490
0
    double dfX = 1.0;
1491
0
    double dfY = 1.0;
1492
0
    double dfZ = 0.0;
1493
0
    GUInt32 nOffset = 0;
1494
1495
0
    OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
1496
0
    OGRMultiLineString *poMLS = new OGRMultiLineString();
1497
1498
    /*---------------------- Reading Primary Line
1499
     * --------------------------------*/
1500
1501
0
    OGRLineString *poLS = new OGRLineString();
1502
1503
0
    for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
1504
0
    {
1505
0
        const char *psCoords = psRecordBuf + nOffset;
1506
1507
0
        GUInt32 nDelta;
1508
0
        if (certifInfo.bDim == 1)
1509
0
        {
1510
0
            nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
1511
0
                                  &dfY, &dfZ);
1512
0
        }
1513
0
        else
1514
0
        {
1515
0
            dfZ = 0.0;
1516
0
            nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
1517
0
                                  &dfY);
1518
0
        }
1519
1520
0
        if (nDelta == 0)
1521
0
            break;
1522
0
        nOffset += nDelta;
1523
1524
0
        poLS->addPoint(dfX, dfY, dfZ);
1525
0
    }
1526
1527
0
    poMLS->addGeometry(poLS);
1528
1529
    /*------------------     READING TEXT VALUE
1530
     * --------------------------------*/
1531
0
    CPLString soText;
1532
1533
0
    if (certifInfo.bHasTextSign)
1534
0
    {
1535
0
        if (nOffset + 1 > nBufLen)
1536
0
            return poFeature;
1537
0
        const char *pszTxt = psRecordBuf + nOffset;
1538
0
        GByte nTextL = (GByte)*pszTxt;
1539
0
        if (nOffset + 1 + nTextL > nBufLen)
1540
0
            return poFeature;
1541
1542
0
        char *pszTextBuf = (char *)CPLMalloc(nTextL + 1);
1543
1544
0
        strncpy(pszTextBuf, (pszTxt + 1), nTextL);
1545
0
        pszTextBuf[nTextL] = '\0';
1546
1547
        // TODO: Check encoding from sxf
1548
0
        char *pszRecoded = CPLRecode(pszTextBuf, "CP1251", CPL_ENC_UTF8);
1549
0
        soText += pszRecoded;
1550
0
        CPLFree(pszRecoded);
1551
1552
0
        CPLFree(pszTextBuf);
1553
1554
0
        nOffset += nTextL + 2;
1555
0
    }
1556
1557
    /*---------------------- Reading Sub Lines
1558
     * --------------------------------*/
1559
1560
0
    for (int count = 0; count < certifInfo.nSubObjectCount; count++)
1561
0
    {
1562
0
        poLS->empty();
1563
1564
0
        if (nOffset + 4 > nBufLen)
1565
0
            break;
1566
1567
0
        GUInt16 nSubObj = 0;
1568
0
        memcpy(&nSubObj, psRecordBuf + nOffset, 2);
1569
0
        CPL_LSBPTR16(&nSubObj);
1570
1571
0
        GUInt16 nCoords = 0;
1572
0
        memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
1573
0
        CPL_LSBPTR16(&nCoords);
1574
1575
0
        nOffset += 4;
1576
1577
0
        for (int i = 0; i < nCoords; i++)
1578
0
        {
1579
0
            const char *psCoords = psRecordBuf + nOffset;
1580
0
            GUInt32 nDelta;
1581
0
            if (certifInfo.bDim == 1)
1582
0
            {
1583
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1584
0
                                      &dfX, &dfY, &dfZ);
1585
0
            }
1586
0
            else
1587
0
            {
1588
0
                dfZ = 0.0;
1589
0
                nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
1590
0
                                      &dfX, &dfY);
1591
0
            }
1592
1593
0
            if (nDelta == 0)
1594
0
                break;
1595
0
            nOffset += nDelta;
1596
1597
0
            poLS->addPoint(dfX, dfY, dfZ);
1598
0
        }
1599
1600
0
        poMLS->addGeometry(poLS);
1601
1602
0
        if (certifInfo.bHasTextSign)
1603
0
        {
1604
0
            if (nOffset + 1 > nBufLen)
1605
0
                return poFeature;
1606
0
            const char *pszTxt = psRecordBuf + nOffset;
1607
0
            GByte nTextL = (GByte)*pszTxt;
1608
0
            if (nOffset + 1 + nTextL > nBufLen)
1609
0
                return poFeature;
1610
1611
0
            char *pszTextBuf = (char *)CPLMalloc(nTextL + 1);
1612
1613
0
            strncpy(pszTextBuf, (pszTxt + 1), nTextL);
1614
0
            pszTextBuf[nTextL] = '\0';
1615
1616
            // TODO: Check encoding from sxf
1617
0
            char *pszRecoded = CPLRecode(pszTextBuf, "CP1251", CPL_ENC_UTF8);
1618
0
            soText += " " + CPLString(pszRecoded);
1619
0
            CPLFree(pszRecoded);
1620
1621
0
            CPLFree(pszTextBuf);
1622
1623
0
            nOffset += nTextL + 2;
1624
0
        }
1625
0
    }  // for
1626
1627
0
    delete poLS;
1628
0
    poFeature->SetGeometryDirectly(poMLS);
1629
1630
0
    poFeature->SetField("TEXT", soText);
1631
0
    return poFeature;
1632
0
}
1633
1634
const char *OGRSXFLayer::GetFIDColumn()
1635
0
{
1636
0
    return sFIDColumn_.c_str();
1637
0
}