• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 14945877415

10 May 2025 01:37PM UTC coverage: 70.838% (+0.004%) from 70.834%
14945877415

Pull #12331

github

web-flow
Merge e74fde6a5 into a1ee70739
Pull Request #12331: GDALG: do not Open() in update mode, and 100% code coverage

12 of 12 new or added lines in 2 files covered. (100.0%)

73 existing lines in 35 files now uncovered.

565410 of 798178 relevant lines covered (70.84%)

234821.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.33
/frmts/map/mapdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  OziExplorer .MAP Driver
4
 * Purpose:  GDALDataset driver for OziExplorer .MAP files
5
 * Author:   Jean-Claude Repetto, <jrepetto at @free dot fr>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2012, Jean-Claude Repetto
9
 * Copyright (c) 2012, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "gdal_frmts.h"
15
#include "gdal_pam.h"
16
#include "gdal_proxy.h"
17
#include "ogr_geometry.h"
18
#include "ogr_spatialref.h"
19

20
/************************************************************************/
21
/* ==================================================================== */
22
/*                                MAPDataset                            */
23
/* ==================================================================== */
24
/************************************************************************/
25

26
class MAPDataset final : public GDALDataset
27
{
28
    GDALDataset *poImageDS;
29

30
    OGRSpatialReference m_oSRS{};
31
    int bGeoTransformValid;
32
    double adfGeoTransform[6];
33
    int nGCPCount;
34
    GDAL_GCP *pasGCPList;
35
    OGRPolygon *poNeatLine;
36
    CPLString osImgFilename;
37

38
  public:
39
    MAPDataset();
40
    virtual ~MAPDataset();
41

42
    const OGRSpatialReference *GetSpatialRef() const override;
43
    virtual CPLErr GetGeoTransform(double *) override;
44
    virtual int GetGCPCount() override;
45
    const OGRSpatialReference *GetGCPSpatialRef() const override;
46
    virtual const GDAL_GCP *GetGCPs() override;
47
    virtual char **GetFileList() override;
48

49
    virtual int CloseDependentDatasets() override;
50

51
    static GDALDataset *Open(GDALOpenInfo *);
52
    static int Identify(GDALOpenInfo *poOpenInfo);
53
};
54

55
/************************************************************************/
56
/* ==================================================================== */
57
/*                         MAPWrapperRasterBand                         */
58
/* ==================================================================== */
59
/************************************************************************/
60
class MAPWrapperRasterBand final : public GDALProxyRasterBand
61
{
62
    GDALRasterBand *poBaseBand;
63

64
  protected:
65
    virtual GDALRasterBand *
66
    RefUnderlyingRasterBand(bool /*bForceOpen*/) const override
×
67
    {
68
        return poBaseBand;
×
69
    }
70

71
  public:
72
    explicit MAPWrapperRasterBand(GDALRasterBand *poBaseBandIn)
×
73
    {
×
74
        this->poBaseBand = poBaseBandIn;
×
75
        eDataType = poBaseBand->GetRasterDataType();
×
76
        poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
×
77
    }
×
78

79
    ~MAPWrapperRasterBand()
×
80
    {
×
81
    }
×
82
};
83

84
/************************************************************************/
85
/* ==================================================================== */
86
/*                             MAPDataset                               */
87
/* ==================================================================== */
88
/************************************************************************/
89

90
MAPDataset::MAPDataset()
×
91
    : poImageDS(nullptr), bGeoTransformValid(false), nGCPCount(0),
92
      pasGCPList(nullptr), poNeatLine(nullptr)
×
93
{
94
    m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
×
95
    adfGeoTransform[0] = 0.0;
×
96
    adfGeoTransform[1] = 1.0;
×
97
    adfGeoTransform[2] = 0.0;
×
98
    adfGeoTransform[3] = 0.0;
×
99
    adfGeoTransform[4] = 0.0;
×
100
    adfGeoTransform[5] = 1.0;
×
101
}
×
102

103
/************************************************************************/
104
/*                            ~MAPDataset()                             */
105
/************************************************************************/
106

107
MAPDataset::~MAPDataset()
×
108

109
{
110
    if (poImageDS != nullptr)
×
111
    {
112
        GDALClose(poImageDS);
×
113
        poImageDS = nullptr;
×
114
    }
115

116
    if (nGCPCount)
×
117
    {
118
        GDALDeinitGCPs(nGCPCount, pasGCPList);
×
119
        CPLFree(pasGCPList);
×
120
    }
121

122
    if (poNeatLine != nullptr)
×
123
    {
124
        delete poNeatLine;
×
125
        poNeatLine = nullptr;
×
126
    }
127
}
×
128

129
/************************************************************************/
130
/*                       CloseDependentDatasets()                       */
131
/************************************************************************/
132

133
int MAPDataset::CloseDependentDatasets()
×
134
{
135
    int bRet = GDALDataset::CloseDependentDatasets();
×
136
    if (poImageDS != nullptr)
×
137
    {
138
        GDALClose(poImageDS);
×
139
        poImageDS = nullptr;
×
140
        bRet = TRUE;
×
141
    }
142
    return bRet;
×
143
}
144

145
/************************************************************************/
146
/*                              Identify()                              */
147
/************************************************************************/
148

149
int MAPDataset::Identify(GDALOpenInfo *poOpenInfo)
53,404✔
150

151
{
152
    if (poOpenInfo->nHeaderBytes < 200 ||
57,233✔
153
        !poOpenInfo->IsExtensionEqualToCI("MAP"))
3,829✔
154
        return FALSE;
53,404✔
155

UNCOV
156
    if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
×
157
               "OziExplorer Map Data File") == nullptr)
158
        return FALSE;
×
159

UNCOV
160
    return TRUE;
×
161
}
162

163
/************************************************************************/
164
/*                                Open()                                */
165
/************************************************************************/
166

167
GDALDataset *MAPDataset::Open(GDALOpenInfo *poOpenInfo)
×
168
{
169
    if (!Identify(poOpenInfo))
×
170
        return nullptr;
×
171

172
    /* -------------------------------------------------------------------- */
173
    /*      Confirm the requested access is supported.                      */
174
    /* -------------------------------------------------------------------- */
175
    if (poOpenInfo->eAccess == GA_Update)
×
176
    {
177
        ReportUpdateNotSupportedByDriver("MAP");
×
178
        return nullptr;
×
179
    }
180

181
    /* -------------------------------------------------------------------- */
182
    /*      Create a corresponding GDALDataset.                             */
183
    /* -------------------------------------------------------------------- */
184

185
    MAPDataset *poDS = new MAPDataset();
×
186

187
    /* -------------------------------------------------------------------- */
188
    /*      Try to load and parse the .MAP file.                            */
189
    /* -------------------------------------------------------------------- */
190

191
    char *pszWKT = nullptr;
×
192
    bool bOziFileOK = CPL_TO_BOOL(
×
193
        GDALLoadOziMapFile(poOpenInfo->pszFilename, poDS->adfGeoTransform,
×
194
                           &pszWKT, &poDS->nGCPCount, &poDS->pasGCPList));
195
    if (pszWKT)
×
196
    {
197
        poDS->m_oSRS.importFromWkt(pszWKT);
×
198
        CPLFree(pszWKT);
×
199
    }
200

201
    if (bOziFileOK && poDS->nGCPCount == 0)
×
202
        poDS->bGeoTransformValid = TRUE;
×
203

204
    /* We need to read again the .map file because the GDALLoadOziMapFile
205
       function does not returns all required data . An API change is necessary
206
       : maybe in GDAL 2.0 ? */
207

208
    char **papszLines = CSLLoad2(poOpenInfo->pszFilename, 200, 200, nullptr);
×
209

210
    if (!papszLines)
×
211
    {
212
        delete poDS;
×
213
        return nullptr;
×
214
    }
215

216
    const int nLines = CSLCount(papszLines);
×
217
    if (nLines < 3)
×
218
    {
219
        delete poDS;
×
220
        CSLDestroy(papszLines);
×
221
        return nullptr;
×
222
    }
223

224
    /* -------------------------------------------------------------------- */
225
    /*      We need to open the image in order to establish                 */
226
    /*      details like the band count and types.                          */
227
    /* -------------------------------------------------------------------- */
228
    poDS->osImgFilename = papszLines[2];
×
229

230
    const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
×
231
    if (CPLIsFilenameRelative(poDS->osImgFilename))
×
232
    {
233
        poDS->osImgFilename =
234
            CPLFormCIFilenameSafe(osPath, poDS->osImgFilename, nullptr);
×
235
    }
236
    else
237
    {
238
        VSIStatBufL sStat;
239
        if (VSIStatL(poDS->osImgFilename, &sStat) != 0)
×
240
        {
241
            poDS->osImgFilename = CPLGetFilename(poDS->osImgFilename);
×
242
            poDS->osImgFilename =
243
                CPLFormCIFilenameSafe(osPath, poDS->osImgFilename, nullptr);
×
244
        }
245
    }
246

247
    /* -------------------------------------------------------------------- */
248
    /*      Try and open the file.                                          */
249
    /* -------------------------------------------------------------------- */
250
    poDS->poImageDS =
×
251
        GDALDataset::FromHandle(GDALOpen(poDS->osImgFilename, GA_ReadOnly));
×
252
    if (poDS->poImageDS == nullptr || poDS->poImageDS->GetRasterCount() == 0)
×
253
    {
254
        CSLDestroy(papszLines);
×
255
        delete poDS;
×
256
        return nullptr;
×
257
    }
258

259
    /* -------------------------------------------------------------------- */
260
    /*      Attach the bands.                                               */
261
    /* -------------------------------------------------------------------- */
262
    poDS->nRasterXSize = poDS->poImageDS->GetRasterXSize();
×
263
    poDS->nRasterYSize = poDS->poImageDS->GetRasterYSize();
×
264
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
×
265
    {
266
        CSLDestroy(papszLines);
×
267
        GDALClose(poDS->poImageDS);
×
268
        delete poDS;
×
269
        return nullptr;
×
270
    }
271

272
    for (int iBand = 1; iBand <= poDS->poImageDS->GetRasterCount(); iBand++)
×
273
        poDS->SetBand(iBand, new MAPWrapperRasterBand(
×
274
                                 poDS->poImageDS->GetRasterBand(iBand)));
×
275

276
    /* -------------------------------------------------------------------- */
277
    /*      Add the neatline/cutline, if required                           */
278
    /* -------------------------------------------------------------------- */
279

280
    /* First, we need to check if it is necessary to define a neatline */
281
    bool bNeatLine = false;
×
282
    for (int iLine = 10; iLine < nLines; iLine++)
×
283
    {
284
        if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
×
285
        {
286
            char **papszTok =
287
                CSLTokenizeString2(papszLines[iLine], ",",
×
288
                                   CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
289

290
            if (CSLCount(papszTok) != 4)
×
291
            {
292
                CSLDestroy(papszTok);
×
293
                continue;
×
294
            }
295

296
            const int x = atoi(papszTok[2]);
×
297
            const int y = atoi(papszTok[3]);
×
298
            if ((x != 0 && x != poDS->nRasterXSize) ||
×
299
                (y != 0 && y != poDS->nRasterYSize))
×
300
            {
301
                bNeatLine = true;
×
302
                CSLDestroy(papszTok);
×
303
                break;
×
304
            }
305
            CSLDestroy(papszTok);
×
306
        }
307
    }
308

309
    /* Create and fill the neatline polygon */
310
    if (bNeatLine)
×
311
    {
312
        poDS->poNeatLine =
×
313
            new OGRPolygon(); /* Create a polygon to store the neatline */
×
314
        OGRLinearRing *poRing = new OGRLinearRing();
×
315

316
        if (poDS->bGeoTransformValid) /* Compute the projected coordinates of
×
317
                                         the corners */
318
        {
319
            for (int iLine = 10; iLine < nLines; iLine++)
×
320
            {
321
                if (STARTS_WITH_CI(papszLines[iLine], "MMPXY,"))
×
322
                {
323
                    char **papszTok = CSLTokenizeString2(
×
324
                        papszLines[iLine], ",",
×
325
                        CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
326

327
                    if (CSLCount(papszTok) != 4)
×
328
                    {
329
                        CSLDestroy(papszTok);
×
330
                        continue;
×
331
                    }
332

333
                    const double x = CPLAtofM(papszTok[2]);
×
334
                    const double y = CPLAtofM(papszTok[3]);
×
335
                    const double X = poDS->adfGeoTransform[0] +
×
336
                                     x * poDS->adfGeoTransform[1] +
×
337
                                     y * poDS->adfGeoTransform[2];
×
338
                    const double Y = poDS->adfGeoTransform[3] +
×
339
                                     x * poDS->adfGeoTransform[4] +
×
340
                                     y * poDS->adfGeoTransform[5];
×
341
                    poRing->addPoint(X, Y);
×
342
                    CPLDebug("CORNER MMPXY", "%f, %f, %f, %f", x, y, X, Y);
×
343
                    CSLDestroy(papszTok);
×
344
                }
345
            }
346
        }
347
        else /* Convert the geographic coordinates to projected coordinates */
348
        {
349
            OGRCoordinateTransformation *poTransform = nullptr;
×
350
            if (!poDS->m_oSRS.IsEmpty())
×
351
            {
352
                OGRSpatialReference *poLongLat = poDS->m_oSRS.CloneGeogCS();
×
353
                if (poLongLat)
×
354
                {
355
                    poLongLat->SetAxisMappingStrategy(
×
356
                        OAMS_TRADITIONAL_GIS_ORDER);
357
                    poTransform = OGRCreateCoordinateTransformation(
×
358
                        poLongLat, &poDS->m_oSRS);
×
359
                    delete poLongLat;
×
360
                }
361
            }
362

363
            for (int iLine = 10; iLine < nLines; iLine++)
×
364
            {
365
                if (STARTS_WITH_CI(papszLines[iLine], "MMPLL,"))
×
366
                {
367
                    CPLDebug("MMPLL", "%s", papszLines[iLine]);
×
368

369
                    char **papszTok = CSLTokenizeString2(
×
370
                        papszLines[iLine], ",",
×
371
                        CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
372

373
                    if (CSLCount(papszTok) != 4)
×
374
                    {
375
                        CSLDestroy(papszTok);
×
376
                        continue;
×
377
                    }
378

379
                    double dfLon = CPLAtofM(papszTok[2]);
×
380
                    double dfLat = CPLAtofM(papszTok[3]);
×
381

382
                    if (poTransform)
×
383
                        poTransform->Transform(1, &dfLon, &dfLat);
×
384
                    poRing->addPoint(dfLon, dfLat);
×
385
                    CPLDebug("CORNER MMPLL", "%f, %f", dfLon, dfLat);
×
386
                    CSLDestroy(papszTok);
×
387
                }
388
            }
389
            if (poTransform)
×
390
                delete poTransform;
×
391
        }
392

393
        poRing->closeRings();
×
394
        poDS->poNeatLine->addRingDirectly(poRing);
×
395

396
        char *pszNeatLineWkt = nullptr;
×
397
        poDS->poNeatLine->exportToWkt(&pszNeatLineWkt);
×
398
        CPLDebug("NEATLINE", "%s", pszNeatLineWkt);
×
399
        poDS->SetMetadataItem("NEATLINE", pszNeatLineWkt);
×
400
        CPLFree(pszNeatLineWkt);
×
401
    }
402

403
    CSLDestroy(papszLines);
×
404

405
    return poDS;
×
406
}
407

408
/************************************************************************/
409
/*                          GetSpatialRef()                             */
410
/************************************************************************/
411

412
const OGRSpatialReference *MAPDataset::GetSpatialRef() const
×
413
{
414
    return (!m_oSRS.IsEmpty() && nGCPCount == 0) ? &m_oSRS : nullptr;
×
415
}
416

417
/************************************************************************/
418
/*                          GetGeoTransform()                           */
419
/************************************************************************/
420

421
CPLErr MAPDataset::GetGeoTransform(double *padfTransform)
×
422

423
{
424
    memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
×
425

426
    return (nGCPCount == 0) ? CE_None : CE_Failure;
×
427
}
428

429
/************************************************************************/
430
/*                           GetGCPCount()                              */
431
/************************************************************************/
432

433
int MAPDataset::GetGCPCount()
×
434
{
435
    return nGCPCount;
×
436
}
437

438
/************************************************************************/
439
/*                          GetGCPSpatialRef()                          */
440
/************************************************************************/
441

442
const OGRSpatialReference *MAPDataset::GetGCPSpatialRef() const
×
443
{
444
    return (!m_oSRS.IsEmpty() && nGCPCount != 0) ? &m_oSRS : nullptr;
×
445
}
446

447
/************************************************************************/
448
/*                               GetGCPs()                              */
449
/************************************************************************/
450

451
const GDAL_GCP *MAPDataset::GetGCPs()
×
452
{
453
    return pasGCPList;
×
454
}
455

456
/************************************************************************/
457
/*                            GetFileList()                             */
458
/************************************************************************/
459

460
char **MAPDataset::GetFileList()
×
461
{
462
    char **papszFileList = GDALDataset::GetFileList();
×
463

464
    papszFileList = CSLAddString(papszFileList, osImgFilename);
×
465

466
    return papszFileList;
×
467
}
468

469
/************************************************************************/
470
/*                          GDALRegister_MAP()                          */
471
/************************************************************************/
472

473
void GDALRegister_MAP()
1,672✔
474

475
{
476
    if (GDALGetDriverByName("MAP") != nullptr)
1,672✔
477
        return;
282✔
478

479
    GDALDriver *poDriver = new GDALDriver();
1,390✔
480

481
    poDriver->SetDescription("MAP");
1,390✔
482
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,390✔
483
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OziExplorer .MAP");
1,390✔
484
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/map.html");
1,390✔
485

486
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,390✔
487

488
    poDriver->pfnOpen = MAPDataset::Open;
1,390✔
489
    poDriver->pfnIdentify = MAPDataset::Identify;
1,390✔
490

491
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,390✔
492
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc