Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gnm/gnm_frmts/file/gnmfilenetwork.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL/OGR Geography Network support (Geographic Network Model)
4
 * Purpose:  GNM file based generic driver.
5
 * Authors:  Mikhail Gusev (gusevmihs at gmail dot com)
6
 *           Dmitry Baryshnikov, polimax@mail.ru
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2014, Mikhail Gusev
10
 * Copyright (c) 2014-2015, NextGIS <info@nextgis.com>
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included
20
 * in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 ****************************************************************************/
30
31
#include "gnmfile.h"
32
#include "gnm_priv.h"
33
34
0
GNMFileNetwork::GNMFileNetwork() : GNMGenericNetwork()
35
0
{
36
0
    m_pMetadataDS = nullptr;
37
0
    m_pGraphDS = nullptr;
38
0
    m_pFeaturesDS = nullptr;
39
0
}
40
41
GNMFileNetwork::~GNMFileNetwork()
42
0
{
43
0
    FlushCache(true);
44
45
0
    for (std::map<OGRLayer *, GDALDataset *>::iterator it =
46
0
             m_mpLayerDatasetMap.begin();
47
0
         it != m_mpLayerDatasetMap.end(); ++it)
48
0
    {
49
0
        GDALClose(it->second);
50
0
    }
51
52
0
    m_mpLayerDatasetMap.clear();
53
54
0
    GDALClose(m_pGraphDS);
55
0
    GDALClose(m_pFeaturesDS);
56
0
    GDALClose(m_pMetadataDS);
57
0
}
58
59
CPLErr GNMFileNetwork::Open(GDALOpenInfo *poOpenInfo)
60
0
{
61
0
    m_soNetworkFullName = poOpenInfo->pszFilename;
62
0
    char **papszFiles = VSIReadDir(m_soNetworkFullName);
63
0
    if (CSLCount(papszFiles) == 0)
64
0
    {
65
0
        CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' file failed",
66
0
                 m_soNetworkFullName.c_str());
67
0
        return CE_Failure;
68
0
    }
69
70
    // search for metadata file
71
0
    CPLString soMetadatafile;
72
0
    for (int i = 0; papszFiles[i] != nullptr; i++)
73
0
    {
74
0
        if (EQUAL(papszFiles[i], ".") || EQUAL(papszFiles[i], ".."))
75
0
            continue;
76
77
0
        if (EQUAL(CPLGetBasenameSafe(papszFiles[i]).c_str(), GNM_SYSLAYER_META))
78
0
        {
79
0
            soMetadatafile = CPLFormFilenameSafe(m_soNetworkFullName,
80
0
                                                 papszFiles[i], nullptr);
81
0
            break;
82
0
        }
83
0
    }
84
85
0
    CSLDestroy(papszFiles);
86
87
0
    m_pMetadataDS = (GDALDataset *)GDALOpenEx(soMetadatafile,
88
0
                                              GDAL_OF_VECTOR | GDAL_OF_UPDATE,
89
0
                                              nullptr, nullptr, nullptr);
90
0
    if (nullptr == m_pMetadataDS)
91
0
    {
92
0
        CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' file failed",
93
0
                 m_soNetworkFullName.c_str());
94
0
        return CE_Failure;
95
0
    }
96
97
0
    if (LoadMetadataLayer(m_pMetadataDS) != CE_None)
98
0
    {
99
0
        return CE_Failure;
100
0
    }
101
102
0
    m_poLayerDriver = m_pMetadataDS->GetDriver();
103
0
    const CPLString osExt = CPLGetExtensionSafe(soMetadatafile);
104
105
0
    const CPLString soGraphfile =
106
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SYSLAYER_GRAPH, osExt);
107
0
    m_pGraphDS =
108
0
        (GDALDataset *)GDALOpenEx(soGraphfile, GDAL_OF_VECTOR | GDAL_OF_UPDATE,
109
0
                                  nullptr, nullptr, nullptr);
110
0
    if (nullptr == m_pGraphDS)
111
0
    {
112
0
        CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' file failed",
113
0
                 m_soNetworkFullName.c_str());
114
0
        return CE_Failure;
115
0
    }
116
117
0
    if (LoadGraphLayer(m_pGraphDS) != CE_None)
118
0
    {
119
0
        return CE_Failure;
120
0
    }
121
122
0
    const CPLString soFeaturesfile =
123
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SYSLAYER_FEATURES, osExt);
124
0
    m_pFeaturesDS = (GDALDataset *)GDALOpenEx(soFeaturesfile,
125
0
                                              GDAL_OF_VECTOR | GDAL_OF_UPDATE,
126
0
                                              nullptr, nullptr, nullptr);
127
0
    if (nullptr == m_pFeaturesDS)
128
0
    {
129
0
        CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' file failed",
130
0
                 m_soNetworkFullName.c_str());
131
0
        return CE_Failure;
132
0
    }
133
134
0
    if (LoadFeaturesLayer(m_pFeaturesDS) != CE_None)
135
0
    {
136
0
        return CE_Failure;
137
0
    }
138
139
0
    return CE_None;
140
0
}
141
142
int GNMFileNetwork::CheckNetworkExist(const char *pszFilename,
143
                                      CSLConstList papszOptions)
144
0
{
145
    // check if path exist
146
    // if path exist check if network already present and OVERWRITE option
147
    // else create the path
148
149
0
    const bool bOverwrite = CPLFetchBool(papszOptions, "OVERWRITE", false);
150
151
0
    if (m_soName.empty())
152
0
    {
153
0
        const char *pszNetworkName =
154
0
            CSLFetchNameValue(papszOptions, GNM_MD_NAME);
155
156
0
        if (nullptr != pszNetworkName)
157
0
        {
158
0
            m_soName = pszNetworkName;
159
0
        }
160
0
    }
161
162
0
    if (FormPath(pszFilename, papszOptions) != CE_None)
163
0
    {
164
0
        return TRUE;
165
0
    }
166
167
0
    if (CPLCheckForFile((char *)m_soNetworkFullName.c_str(), nullptr))
168
0
    {
169
0
        char **papszFiles = VSIReadDir(m_soNetworkFullName);
170
0
        if (CSLCount(papszFiles) == 0)
171
0
        {
172
0
            return FALSE;
173
0
        }
174
175
        // search for base GNM files
176
0
        for (int i = 0; papszFiles[i] != nullptr; i++)
177
0
        {
178
0
            if (EQUAL(papszFiles[i], ".") || EQUAL(papszFiles[i], ".."))
179
0
                continue;
180
181
0
            const CPLString osBasename = CPLGetBasenameSafe(papszFiles[i]);
182
0
            if (EQUAL(osBasename, GNM_SYSLAYER_META) ||
183
0
                EQUAL(osBasename, GNM_SYSLAYER_GRAPH) ||
184
0
                EQUAL(osBasename, GNM_SYSLAYER_FEATURES) ||
185
0
                EQUAL(papszFiles[i], GNM_SRSFILENAME))
186
0
            {
187
0
                if (bOverwrite)
188
0
                {
189
0
                    const std::string osDeleteFile = CPLFormFilenameSafe(
190
0
                        m_soNetworkFullName, papszFiles[i], nullptr);
191
0
                    CPLDebug("GNM", "Delete file: %s", osDeleteFile.c_str());
192
0
                    if (VSIUnlink(osDeleteFile.c_str()) != 0)
193
0
                    {
194
0
                        return TRUE;
195
0
                    }
196
0
                }
197
0
                else
198
0
                {
199
0
                    return TRUE;
200
0
                }
201
0
            }
202
0
        }
203
0
        CSLDestroy(papszFiles);
204
0
    }
205
0
    else
206
0
    {
207
0
        if (VSIMkdir(m_soNetworkFullName, 0755) != 0)
208
0
        {
209
0
            return TRUE;
210
0
        }
211
0
    }
212
213
0
    return FALSE;
214
0
}
215
216
CPLErr GNMFileNetwork::Delete()
217
0
{
218
0
    CPLErr eResult = GNMGenericNetwork::Delete();
219
0
    if (eResult != CE_None)
220
0
        return eResult;
221
222
    // check if folder empty
223
0
    char **papszFiles = VSIReadDir(m_soNetworkFullName);
224
0
    bool bIsEmpty = true;
225
0
    for (int i = 0; papszFiles[i] != nullptr; ++i)
226
0
    {
227
0
        if (!(EQUAL(papszFiles[i], "..") || EQUAL(papszFiles[i], ".")))
228
0
        {
229
0
            bIsEmpty = false;
230
0
            break;
231
0
        }
232
0
    }
233
234
0
    CSLDestroy(papszFiles);
235
236
0
    if (!bIsEmpty)
237
0
    {
238
0
        return eResult;
239
0
    }
240
0
    return VSIRmdir(m_soNetworkFullName) == 0 ? CE_None : CE_Failure;
241
0
}
242
243
CPLErr GNMFileNetwork::CreateMetadataLayerFromFile(const char *pszFilename,
244
                                                   int nVersion,
245
                                                   CSLConstList papszOptions)
246
0
{
247
0
    CPLErr eResult = CheckLayerDriver(GNM_MD_DEFAULT_FILE_FORMAT, papszOptions);
248
0
    if (CE_None != eResult)
249
0
        return eResult;
250
251
0
    eResult = FormPath(pszFilename, papszOptions);
252
0
    if (CE_None != eResult)
253
0
        return eResult;
254
255
0
    const char *pszExt = m_poLayerDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
256
0
    const CPLString osDSFileName =
257
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SYSLAYER_META, pszExt);
258
259
0
    m_pMetadataDS =
260
0
        m_poLayerDriver->Create(osDSFileName, 0, 0, 0, GDT_Unknown, nullptr);
261
0
    if (nullptr == m_pMetadataDS)
262
0
    {
263
0
        CPLError(CE_Failure, CPLE_AppDefined, "Creation of '%s' file failed",
264
0
                 osDSFileName.c_str());
265
0
        return CE_Failure;
266
0
    }
267
268
0
    return GNMGenericNetwork::CreateMetadataLayer(m_pMetadataDS, nVersion, 254);
269
0
}
270
271
CPLErr GNMFileNetwork::StoreNetworkSrs()
272
0
{
273
0
    if (m_oSRS.IsEmpty())
274
0
        return CE_None;
275
0
    const std::string osSrsFileName =
276
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SRSFILENAME, nullptr);
277
0
    VSILFILE *fpSrsPrj = VSIFOpenL(osSrsFileName.c_str(), "w");
278
0
    if (fpSrsPrj != nullptr)
279
0
    {
280
0
        char *pszWKT = nullptr;
281
0
        m_oSRS.exportToWkt(&pszWKT);
282
0
        if (pszWKT && VSIFWriteL(pszWKT, (int)strlen(pszWKT), 1, fpSrsPrj) != 1)
283
0
        {
284
0
            CPLFree(pszWKT);
285
0
            CPLError(CE_Failure, CPLE_AppDefined,
286
0
                     "Write SRS failed, disk full?");
287
0
            VSIFCloseL(fpSrsPrj);
288
0
            return CE_Failure;
289
0
        }
290
0
        CPLFree(pszWKT);
291
0
        VSIFCloseL(fpSrsPrj);
292
0
    }
293
0
    return CE_None;
294
0
}
295
296
CPLErr GNMFileNetwork::LoadNetworkSrs()
297
0
{
298
0
    const std::string osSrsFileName =
299
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SRSFILENAME, nullptr);
300
0
    char **papszLines = CSLLoad(osSrsFileName.c_str());
301
0
    if (nullptr == papszLines)
302
0
    {
303
0
        CPLError(CE_Failure, CPLE_AppDefined, "Loading of '%s' layer failed",
304
0
                 GNM_SYSLAYER_META);
305
0
        return CE_Failure;
306
0
    }
307
308
0
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
309
0
    m_oSRS.importFromWkt(papszLines[0]);
310
311
0
    CSLDestroy(papszLines);
312
313
0
    return CE_None;
314
0
}
315
316
CPLErr GNMFileNetwork::DeleteMetadataLayer()
317
0
{
318
0
    if (nullptr != m_pMetadataDS)
319
0
    {
320
0
        const std::string osSrsFileName =
321
0
            CPLFormFilenameSafe(m_soNetworkFullName, GNM_SRSFILENAME, nullptr);
322
0
        VSIUnlink(
323
0
            osSrsFileName
324
0
                .c_str());  // just try to delete as file may not be existed
325
0
        return m_pMetadataDS->DeleteLayer(0) == OGRERR_NONE ? CE_None
326
0
                                                            : CE_Failure;
327
0
    }
328
0
    return CE_Failure;
329
0
}
330
331
CPLErr GNMFileNetwork::CreateGraphLayerFromFile(const char *pszFilename,
332
                                                CSLConstList papszOptions)
333
0
{
334
0
    CPLErr eResult = CheckLayerDriver(GNM_MD_DEFAULT_FILE_FORMAT, papszOptions);
335
0
    if (CE_None != eResult)
336
0
        return eResult;
337
338
0
    eResult = FormPath(pszFilename, papszOptions);
339
0
    if (CE_None != eResult)
340
0
        return eResult;
341
342
0
    const char *pszExt = m_poLayerDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
343
0
    const CPLString osDSFileName =
344
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SYSLAYER_GRAPH, pszExt);
345
346
0
    m_pGraphDS =
347
0
        m_poLayerDriver->Create(osDSFileName, 0, 0, 0, GDT_Unknown, nullptr);
348
349
0
    if (m_pGraphDS == nullptr)
350
0
    {
351
0
        CPLError(CE_Failure, CPLE_AppDefined, "Creation of '%s' file failed",
352
0
                 osDSFileName.c_str());
353
0
        return CE_Failure;
354
0
    }
355
356
0
    return GNMGenericNetwork::CreateGraphLayer(m_pGraphDS);
357
0
}
358
359
CPLErr GNMFileNetwork::DeleteGraphLayer()
360
0
{
361
0
    if (nullptr != m_pGraphDS)
362
0
    {
363
0
        return m_pGraphDS->DeleteLayer(0) == OGRERR_NONE ? CE_None : CE_Failure;
364
0
    }
365
0
    return CE_Failure;
366
0
}
367
368
CPLErr GNMFileNetwork::CreateFeaturesLayerFromFile(const char *pszFilename,
369
                                                   CSLConstList papszOptions)
370
0
{
371
0
    CPLErr eResult = CheckLayerDriver(GNM_MD_DEFAULT_FILE_FORMAT, papszOptions);
372
0
    if (CE_None != eResult)
373
0
        return eResult;
374
375
0
    eResult = FormPath(pszFilename, papszOptions);
376
0
    if (CE_None != eResult)
377
0
        return eResult;
378
379
0
    const char *pszExt = m_poLayerDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
380
0
    const CPLString osDSFileName =
381
0
        CPLFormFilenameSafe(m_soNetworkFullName, GNM_SYSLAYER_FEATURES, pszExt);
382
383
0
    m_pFeaturesDS =
384
0
        m_poLayerDriver->Create(osDSFileName, 0, 0, 0, GDT_Unknown, nullptr);
385
386
0
    if (m_pFeaturesDS == nullptr)
387
0
    {
388
0
        CPLError(CE_Failure, CPLE_AppDefined, "Creation of '%s' file failed",
389
0
                 osDSFileName.c_str());
390
0
        return CE_Failure;
391
0
    }
392
393
0
    return GNMGenericNetwork::CreateFeaturesLayer(m_pFeaturesDS);
394
0
}
395
396
CPLErr GNMFileNetwork::DeleteFeaturesLayer()
397
0
{
398
0
    if (nullptr != m_pFeaturesDS)
399
0
    {
400
0
        return m_pFeaturesDS->DeleteLayer(0) == OGRERR_NONE ? CE_None
401
0
                                                            : CE_Failure;
402
0
    }
403
0
    return CE_Failure;
404
0
}
405
406
CPLErr GNMFileNetwork::DeleteNetworkLayers()
407
0
{
408
0
    while (GetLayerCount() > 0)
409
0
    {
410
0
        OGRErr eErr = DeleteLayer(0);
411
0
        if (eErr != OGRERR_NONE)
412
0
            return CE_Failure;
413
0
    }
414
0
    return CE_None;
415
0
}
416
417
CPLErr GNMFileNetwork::LoadNetworkLayer(const char *pszLayername)
418
0
{
419
    // check if not loaded
420
0
    for (size_t i = 0; i < m_apoLayers.size(); ++i)
421
0
    {
422
0
        if (EQUAL(m_apoLayers[i]->GetName(), pszLayername))
423
0
            return CE_None;
424
0
    }
425
426
0
    const char *pszExt = m_poLayerDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
427
428
0
    const CPLString soFile =
429
0
        CPLFormFilenameSafe(m_soNetworkFullName, pszLayername, pszExt);
430
0
    GDALDataset *poDS = (GDALDataset *)GDALOpenEx(
431
0
        soFile, GDAL_OF_VECTOR | GDAL_OF_UPDATE, nullptr, nullptr, nullptr);
432
0
    if (nullptr == poDS)
433
0
    {
434
0
        CPLError(CE_Failure, CPLE_OpenFailed, "Open '%s' file failed",
435
0
                 soFile.c_str());
436
0
        return CE_Failure;
437
0
    }
438
439
0
    OGRLayer *poLayer = poDS->GetLayer(0);
440
0
    if (nullptr == poLayer)
441
0
    {
442
0
        CPLError(CE_Failure, CPLE_OpenFailed, "Layer '%s' is not exist",
443
0
                 pszLayername);
444
0
        return CE_Failure;
445
0
    }
446
447
0
    CPLDebug("GNM", "Layer '%s' loaded", poLayer->GetName());
448
449
0
    GNMGenericLayer *pGNMLayer = new GNMGenericLayer(poLayer, this);
450
0
    m_apoLayers.push_back(pGNMLayer);
451
0
    m_mpLayerDatasetMap[pGNMLayer] = poDS;
452
453
0
    return CE_None;
454
0
}
455
456
bool GNMFileNetwork::CheckStorageDriverSupport(const char *pszDriverName)
457
0
{
458
0
    if (EQUAL(pszDriverName, GNM_MD_DEFAULT_FILE_FORMAT))
459
0
        return true;
460
    // TODO: expand this list with supported OGR direvers
461
0
    return false;
462
0
}
463
464
CPLErr GNMFileNetwork::FormPath(const char *pszFilename,
465
                                CSLConstList papszOptions)
466
0
{
467
0
    if (m_soNetworkFullName.empty())
468
0
    {
469
0
        const char *pszNetworkName =
470
0
            CSLFetchNameValue(papszOptions, GNM_MD_NAME);
471
0
        if (nullptr == pszNetworkName)
472
0
        {
473
0
            CPLError(CE_Failure, CPLE_IllegalArg,
474
0
                     "The network name should be present");
475
0
            return CE_Failure;
476
0
        }
477
0
        m_soNetworkFullName =
478
0
            CPLFormFilenameSafe(pszFilename, pszNetworkName, nullptr);
479
480
0
        CPLDebug("GNM", "Network name: %s", m_soNetworkFullName.c_str());
481
0
    }
482
0
    return CE_None;
483
0
}
484
485
int GNMFileNetwork::CloseDependentDatasets()
486
0
{
487
0
    size_t nCount = m_mpLayerDatasetMap.size();
488
0
    for (std::map<OGRLayer *, GDALDataset *>::iterator it =
489
0
             m_mpLayerDatasetMap.begin();
490
0
         it != m_mpLayerDatasetMap.end(); ++it)
491
0
    {
492
0
        GDALClose(it->second);
493
0
    }
494
495
0
    m_mpLayerDatasetMap.clear();
496
497
0
    GNMGenericNetwork::CloseDependentDatasets();
498
499
0
    return nCount > 0 ? TRUE : FALSE;
500
0
}
501
502
OGRErr GNMFileNetwork::DeleteLayer(int nIndex)
503
0
{
504
0
    OGRLayer *pLayer = GetLayer(nIndex);
505
506
0
    GDALDataset *poDS = m_mpLayerDatasetMap[pLayer];
507
0
    if (nullptr == poDS)
508
0
    {
509
0
        return OGRERR_FAILURE;
510
0
    }
511
512
0
    CPLDebug("GNM", "Delete network layer '%s'", pLayer->GetName());
513
514
0
    if (poDS->DeleteLayer(0) != OGRERR_NONE)
515
0
    {
516
0
        return OGRERR_FAILURE;
517
0
    }
518
519
0
    GDALClose(poDS);
520
521
    // remove pointer from map
522
0
    m_mpLayerDatasetMap.erase(pLayer);
523
524
0
    return GNMGenericNetwork::DeleteLayer(nIndex);
525
0
}
526
527
OGRLayer *GNMFileNetwork::ICreateLayer(const char *pszName,
528
                                       const OGRGeomFieldDefn *poGeomFieldDefn,
529
                                       CSLConstList papszOptions)
530
0
{
531
0
    if (nullptr == m_poLayerDriver)
532
0
    {
533
0
        CPLError(CE_Failure, CPLE_AppDefined,
534
0
                 "The network storage format driver is not defined.");
535
0
        return nullptr;
536
0
    }
537
538
0
    const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
539
540
    // check if layer with such name exist
541
0
    for (int i = 0; i < GetLayerCount(); ++i)
542
0
    {
543
0
        OGRLayer *pLayer = GetLayer(i);
544
0
        if (nullptr == pLayer)
545
0
            continue;
546
0
        if (EQUAL(pLayer->GetName(), pszName))
547
0
        {
548
0
            CPLError(CE_Failure, CPLE_IllegalArg,
549
0
                     "The network layer '%s' already exist.", pszName);
550
0
            return nullptr;
551
0
        }
552
0
    }
553
554
    // form path
555
0
    const char *pszExt = m_poLayerDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
556
0
    const CPLString soPath =
557
0
        CPLFormFilenameSafe(m_soNetworkFullName, pszName, pszExt);
558
559
0
    GDALDataset *poDS =
560
0
        m_poLayerDriver->Create(soPath, 0, 0, 0, GDT_Unknown, papszOptions);
561
0
    if (poDS == nullptr)
562
0
    {
563
0
        CPLError(CE_Failure, CPLE_FileIO, "Creation of output file failed.");
564
0
        return nullptr;
565
0
    }
566
567
0
    OGRSpatialReference oSpaRef(m_oSRS);
568
569
0
    OGRLayer *poLayer =
570
0
        poDS->CreateLayer(pszName, &oSpaRef, eGType, papszOptions);
571
0
    if (poLayer == nullptr)
572
0
    {
573
0
        CPLError(CE_Failure, CPLE_FileIO, "Layer creation failed.");
574
0
        GDALClose(poDS);
575
0
        return nullptr;
576
0
    }
577
578
0
    OGRFieldDefn oField(GNM_SYSFIELD_GFID, GNMGFIDInt);
579
0
    if (poLayer->CreateField(&oField) != OGRERR_NONE)
580
0
    {
581
0
        CPLError(CE_Failure, CPLE_FileIO,
582
0
                 "Creating global identificator field failed.");
583
0
        GDALClose(poDS);
584
0
        return nullptr;
585
0
    }
586
587
0
    OGRFieldDefn oFieldBlock(GNM_SYSFIELD_BLOCKED, OFTInteger);
588
0
    if (poLayer->CreateField(&oFieldBlock) != OGRERR_NONE)
589
0
    {
590
0
        CPLError(CE_Failure, CPLE_FileIO, "Creating is blocking field failed.");
591
0
        GDALClose(poDS);
592
0
        return nullptr;
593
0
    }
594
595
0
    GNMGenericLayer *pGNMLayer = new GNMGenericLayer(poLayer, this);
596
0
    m_apoLayers.push_back(pGNMLayer);
597
0
    m_mpLayerDatasetMap[pGNMLayer] = poDS;
598
0
    return pGNMLayer;
599
0
}
600
601
CPLErr GNMFileNetwork::Create(const char *pszFilename,
602
                              CSLConstList papszOptions)
603
0
{
604
    // check required options
605
606
    // check name
607
0
    const char *pszNetworkName = CSLFetchNameValue(papszOptions, GNM_MD_NAME);
608
609
0
    if (nullptr == pszNetworkName)
610
0
    {
611
0
        CPLError(CE_Failure, CPLE_IllegalArg,
612
0
                 "The network name should be present");
613
0
        return CE_Failure;
614
0
    }
615
0
    else
616
0
    {
617
0
        m_soName = pszNetworkName;
618
0
    }
619
620
0
    const char *pszNetworkDescription =
621
0
        CSLFetchNameValue(papszOptions, GNM_MD_DESCR);
622
0
    if (nullptr != pszNetworkDescription)
623
0
        sDescription = pszNetworkDescription;
624
625
    // check Spatial reference
626
0
    const char *pszSRS = CSLFetchNameValue(papszOptions, GNM_MD_SRS);
627
0
    if (nullptr == pszSRS)
628
0
    {
629
0
        CPLError(CE_Failure, CPLE_IllegalArg,
630
0
                 "The network spatial reference should be present");
631
0
        return CE_Failure;
632
0
    }
633
0
    else
634
0
    {
635
0
        OGRSpatialReference spatialRef;
636
0
        spatialRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
637
0
        if (spatialRef.SetFromUserInput(pszSRS) != OGRERR_NONE)
638
0
        {
639
0
            CPLError(CE_Failure, CPLE_IllegalArg,
640
0
                     "The network spatial reference should be present");
641
0
            return CE_Failure;
642
0
        }
643
644
0
        m_oSRS = std::move(spatialRef);
645
0
    }
646
647
0
    int nResult = CheckNetworkExist(pszFilename, papszOptions);
648
649
0
    if (TRUE == nResult)
650
0
    {
651
0
        CPLError(CE_Failure, CPLE_IllegalArg, "The network already exist");
652
0
        return CE_Failure;
653
0
    }
654
655
    // Create the necessary system layers and fields
656
657
    // Create meta layer
658
659
0
    CPLErr eResult =
660
0
        CreateMetadataLayerFromFile(pszFilename, GNM_VERSION_NUM, papszOptions);
661
662
0
    if (CE_None != eResult)
663
0
    {
664
        // an error message should come from function
665
0
        return CE_Failure;
666
0
    }
667
668
    // Create graph layer
669
670
0
    eResult = CreateGraphLayerFromFile(pszFilename, papszOptions);
671
672
0
    if (CE_None != eResult)
673
0
    {
674
0
        DeleteMetadataLayer();
675
0
        return CE_Failure;
676
0
    }
677
678
    // Create features layer
679
680
0
    eResult = CreateFeaturesLayerFromFile(pszFilename, papszOptions);
681
682
0
    if (CE_None != eResult)
683
0
    {
684
0
        DeleteMetadataLayer();
685
0
        DeleteGraphLayer();
686
0
        return CE_Failure;
687
0
    }
688
689
0
    return CE_None;
690
0
}