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

MapServer / MapServer / 19615687753

23 Nov 2025 06:46PM UTC coverage: 41.722% (+0.007%) from 41.715%
19615687753

push

github

web-flow
Output GDAL files: fix from init=epsg:xxxx layers (#7392)

* Output GDAL files: fix from init=epsg:xxxx layers

When e.g. exporting a layer trough WCS whole LAYER.PROJETION is
init=epsg:xxxx with the xxxx code being a custom one in a legacy 'epsg'
text file, loading that projection in msProjectionObj2OGCWKT() and
resulted in an output file without SRS definition

* mapscript/: no longer use SWIG_LINK_LIBRARIES deprecated in CMake 4.2

2 of 4 new or added lines in 1 file covered. (50.0%)

119 existing lines in 3 files now uncovered.

62808 of 150541 relevant lines covered (41.72%)

25205.89 hits per line

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

79.72
/src/mapgdal.cpp
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Implementation of support for output using GDAL.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2002, Frank Warmerdam
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies of this Software or works derived from this Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 * DEALINGS IN THE SOFTWARE.
28
 ****************************************************************************/
29

30
#include "mapserver.h"
31
#include "mapthread.h"
32
#include "mapgdal.h"
33
#include <assert.h>
34

35
#include "cpl_conv.h"
36
#include "cpl_string.h"
37
#include "ogr_srs_api.h"
38

39
#include "gdal.h"
40

41
static int bGDALInitialized = 0;
42

43
/************************************************************************/
44
/*                          msGDALInitialize()                          */
45
/************************************************************************/
46

47
void msGDALInitialize(void)
2,643✔
48

49
{
50
  if (!bGDALInitialized) {
2,643✔
51
    msAcquireLock(TLOCK_GDAL);
782✔
52

53
    GDALAllRegister();
782✔
54
    CPLPushErrorHandler(CPLQuietErrorHandler);
782✔
55
    msReleaseLock(TLOCK_GDAL);
782✔
56

57
    bGDALInitialized = 1;
782✔
58
  }
59
}
2,643✔
60

61
/************************************************************************/
62
/*                           msGDALCleanup()                            */
63
/************************************************************************/
64

65
void msGDALCleanup(void)
2,651✔
66

67
{
68
  if (bGDALInitialized) {
2,651✔
69
    int iRepeat = 5;
70

71
    /*
72
    ** Cleanup any unreferenced but open datasets as will tend
73
    ** to exist due to deferred close requests.  We are careful
74
    ** to only close one file at a time before reflecting the
75
    ** list as closing some datasets may cause others to be
76
    ** closed (subdatasets in a VRT for instance).
77
    */
78
    GDALDatasetH *pahDSList = NULL;
778✔
79
    int nDSCount = 0;
778✔
80
    int bDidSomething;
81

82
    msAcquireLock(TLOCK_GDAL);
778✔
83

84
    do {
85
      int i;
86
      GDALGetOpenDatasets(&pahDSList, &nDSCount);
1,017✔
87
      bDidSomething = FALSE;
88
      for (i = 0; i < nDSCount && !bDidSomething; i++) {
1,267✔
89
        if (GDALReferenceDataset(pahDSList[i]) == 1) {
250✔
90
          GDALClose(pahDSList[i]);
239✔
91
          bDidSomething = TRUE;
92
        } else
93
          GDALDereferenceDataset(pahDSList[i]);
11✔
94
      }
95
    } while (bDidSomething);
1,017✔
96

97
    while (iRepeat--)
4,668✔
98
      CPLPopErrorHandler();
3,890✔
99

100
    msReleaseLock(TLOCK_GDAL);
778✔
101

102
    bGDALInitialized = 0;
778✔
103
  }
104
}
2,651✔
105

106
/************************************************************************/
107
/*                          msCleanVSIDir()                             */
108
/*                                                                      */
109
/*      For the temporary /vsimem/msout directory we need to be sure    */
110
/*      things are clean before we start, and after we are done.        */
111
/************************************************************************/
112

113
void msCleanVSIDir(const char *pszDir)
38✔
114

115
{
116
  char **papszFiles = CPLReadDir(pszDir);
38✔
117
  int i, nFileCount = CSLCount(papszFiles);
38✔
118

119
  for (i = 0; i < nFileCount; i++) {
56✔
120
    if (strcasecmp(papszFiles[i], ".") == 0 ||
18✔
121
        strcasecmp(papszFiles[i], "..") == 0)
18✔
122
      continue;
×
123

124
    VSIUnlink(CPLFormFilename(pszDir, papszFiles[i], NULL));
18✔
125
  }
126

127
  CSLDestroy(papszFiles);
38✔
128
}
38✔
129

130
/************************************************************************/
131
/*                          msSaveImageGDAL()                           */
132
/************************************************************************/
133

134
int msSaveImageGDAL(mapObj *map, imageObj *image, const char *filenameIn)
210✔
135

136
{
137
  int bFileIsTemporary = MS_FALSE;
138
  GDALDatasetH hMemDS, hOutputDS;
139
  GDALDriverH hMemDriver, hOutputDriver;
140
  int nBands = 1;
141
  int iLine;
142
  outputFormatObj *format = image->format;
210✔
143
  rasterBufferObj rb;
144
  GDALDataType eDataType = GDT_Byte;
145
  int bUseXmp = MS_FALSE;
146
  const char *filename = NULL;
147
  char *filenameToFree = NULL;
148
  const char *gdal_driver_shortname = format->driver + 5;
210✔
149

150
  msGDALInitialize();
210✔
151
  memset(&rb, 0, sizeof(rasterBufferObj));
152

153
#ifdef USE_EXEMPI
154
  if (map != NULL) {
210✔
155
    bUseXmp = msXmpPresent(map);
209✔
156
  }
157
#endif
158

159
  /* -------------------------------------------------------------------- */
160
  /*      Identify the proposed output driver.                            */
161
  /* -------------------------------------------------------------------- */
162
  msAcquireLock(TLOCK_GDAL);
210✔
163
  hOutputDriver = GDALGetDriverByName(gdal_driver_shortname);
210✔
164
  if (hOutputDriver == NULL) {
210✔
165
    msReleaseLock(TLOCK_GDAL);
×
166
    msSetError(MS_MISCERR, "Failed to find %s driver.", "msSaveImageGDAL()",
×
167
               gdal_driver_shortname);
168
    return MS_FAILURE;
×
169
  }
170

171
  /* -------------------------------------------------------------------- */
172
  /*      We will need to write the output to a temporary file and        */
173
  /*      then stream to stdout if no filename is passed.  If the         */
174
  /*      driver supports virtualio then we hold the temporary file in    */
175
  /*      memory, otherwise we try to put it in a reasonable temporary    */
176
  /*      file location.                                                  */
177
  /* -------------------------------------------------------------------- */
178
  if (filenameIn == NULL) {
210✔
179
    const char *pszExtension = format->extension;
21✔
180
    if (pszExtension == NULL)
21✔
181
      pszExtension = "img.tmp";
182

183
    if (bUseXmp == MS_FALSE &&
42✔
184
        msGDALDriverSupportsVirtualIOOutput(hOutputDriver)) {
21✔
185
      msCleanVSIDir("/vsimem/msout");
17✔
186
      filenameToFree = msTmpFile(map, NULL, "/vsimem/msout/", pszExtension);
17✔
187
    }
188

189
    if (filenameToFree == NULL && map != NULL)
21✔
190
      filenameToFree = msTmpFile(map, map->mappath, NULL, pszExtension);
4✔
191
    else if (filenameToFree == NULL) {
17✔
192
      filenameToFree = msTmpFile(map, NULL, NULL, pszExtension);
×
193
    }
194
    filename = filenameToFree;
195

196
    bFileIsTemporary = MS_TRUE;
197
  } else {
198
    filename = filenameIn;
199
  }
200

201
  /* -------------------------------------------------------------------- */
202
  /*      Establish the characteristics of our memory, and final          */
203
  /*      dataset.                                                        */
204
  /* -------------------------------------------------------------------- */
205

206
  if (format->imagemode == MS_IMAGEMODE_RGB) {
210✔
207
    nBands = 3;
208
    assert(MS_RENDERER_PLUGIN(format) && format->vtable->supports_pixel_buffer);
209
    if (MS_UNLIKELY(MS_FAILURE ==
14✔
210
                    format->vtable->getRasterBufferHandle(image, &rb))) {
211
      msReleaseLock(TLOCK_GDAL);
×
212
      msFree(filenameToFree);
×
213
      return MS_FAILURE;
×
214
    }
215
  } else if (format->imagemode == MS_IMAGEMODE_RGBA) {
216
    nBands = 4;
217
    assert(MS_RENDERER_PLUGIN(format) && format->vtable->supports_pixel_buffer);
218
    if (MS_UNLIKELY(MS_FAILURE ==
18✔
219
                    format->vtable->getRasterBufferHandle(image, &rb))) {
220
      msReleaseLock(TLOCK_GDAL);
×
221
      msFree(filenameToFree);
×
222
      return MS_FAILURE;
×
223
    }
224
  } else if (format->imagemode == MS_IMAGEMODE_INT16) {
225
    nBands = format->bands;
27✔
226
    eDataType = GDT_Int16;
227
  } else if (format->imagemode == MS_IMAGEMODE_FLOAT32) {
228
    nBands = format->bands;
13✔
229
    eDataType = GDT_Float32;
230
  } else if (format->imagemode == MS_IMAGEMODE_BYTE) {
231
    nBands = format->bands;
138✔
232
    eDataType = GDT_Byte;
233
  } else {
234
    msReleaseLock(TLOCK_GDAL);
×
235
    msSetError(MS_MEMERR, "Unknown format. This is a bug.",
×
236
               "msSaveImageGDAL()");
237
    msFree(filenameToFree);
×
238
    return MS_FAILURE;
×
239
  }
240

241
  /* -------------------------------------------------------------------- */
242
  /*      Create a memory dataset which we can use as a source for a      */
243
  /*      CreateCopy().                                                   */
244
  /* -------------------------------------------------------------------- */
245
  hMemDriver = GDALGetDriverByName("MEM");
210✔
246
  if (hMemDriver == NULL) {
210✔
247
    msReleaseLock(TLOCK_GDAL);
×
248
    msSetError(MS_MISCERR, "Failed to find MEM driver.", "msSaveImageGDAL()");
×
249
    msFree(filenameToFree);
×
250
    return MS_FAILURE;
×
251
  }
252

253
  hMemDS = GDALCreate(hMemDriver, "msSaveImageGDAL_temp", image->width,
210✔
254
                      image->height, nBands, eDataType, NULL);
255
  if (hMemDS == NULL) {
210✔
256
    msReleaseLock(TLOCK_GDAL);
×
257
    msSetError(MS_MISCERR, "Failed to create MEM dataset.",
×
258
               "msSaveImageGDAL()");
259
    msFree(filenameToFree);
×
260
    return MS_FAILURE;
×
261
  }
262

263
  /* -------------------------------------------------------------------- */
264
  /*      Copy the gd image into the memory dataset.                      */
265
  /* -------------------------------------------------------------------- */
266
  for (iLine = 0; iLine < image->height; iLine++) {
15,917✔
267
    int iBand;
268

269
    for (iBand = 0; iBand < nBands; iBand++) {
61,192✔
270
      CPLErr eErr;
271
      GDALRasterBandH hBand = GDALGetRasterBand(hMemDS, iBand + 1);
45,485✔
272

273
      if (format->imagemode == MS_IMAGEMODE_INT16) {
45,485✔
274
        eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1,
1,200✔
275
                            image->img.raw_16bit + iLine * image->width +
1,200✔
276
                                iBand * image->width * image->height,
1,200✔
277
                            image->width, 1, GDT_Int16, 2, 0);
278

279
      } else if (format->imagemode == MS_IMAGEMODE_FLOAT32) {
44,285✔
280
        eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1,
1,077✔
281
                            image->img.raw_float + iLine * image->width +
1,077✔
282
                                iBand * image->width * image->height,
1,077✔
283
                            image->width, 1, GDT_Float32, 4, 0);
284
      } else if (format->imagemode == MS_IMAGEMODE_BYTE) {
43,208✔
285
        eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1,
11,233✔
286
                            image->img.raw_byte + iLine * image->width +
11,233✔
287
                                iBand * image->width * image->height,
11,233✔
288
                            image->width, 1, GDT_Byte, 1, 0);
289
      } else {
290
        GByte *pabyData;
291
        unsigned char *pixptr = NULL;
292
        assert(rb.type == MS_BUFFER_BYTE_RGBA);
293
        switch (iBand) {
31,975✔
294
        case 0:
9,005✔
295
          pixptr = rb.data.rgba.r;
9,005✔
296
          break;
9,005✔
297
        case 1:
9,005✔
298
          pixptr = rb.data.rgba.g;
9,005✔
299
          break;
9,005✔
300
        case 2:
9,005✔
301
          pixptr = rb.data.rgba.b;
9,005✔
302
          break;
9,005✔
303
        case 3:
4,960✔
304
          pixptr = rb.data.rgba.a;
4,960✔
305
          break;
4,960✔
306
        }
307
        assert(pixptr);
308
        if (pixptr == NULL) {
31,975✔
309
          msReleaseLock(TLOCK_GDAL);
×
310
          msSetError(MS_MISCERR, "Missing RGB or A buffer.\n",
×
311
                     "msSaveImageGDAL()");
312
          GDALClose(hMemDS);
×
313
          msFree(filenameToFree);
×
314
          return MS_FAILURE;
×
315
        }
316

317
        pabyData = (GByte *)(pixptr + iLine * rb.data.rgba.row_step);
31,975✔
318

319
        if (rb.data.rgba.a == NULL || iBand == 3) {
31,975✔
320
          eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1,
17,095✔
321
                              pabyData, image->width, 1, GDT_Byte,
322
                              rb.data.rgba.pixel_step, 0);
17,095✔
323
        } else { /* We need to un-pre-multiple RGB by alpha. */
324
          GByte *pabyUPM = (GByte *)malloc(image->width);
14,880✔
325
          GByte *pabyAlpha =
326
              (GByte *)(rb.data.rgba.a + iLine * rb.data.rgba.row_step);
14,880✔
327
          int i;
328

329
          for (i = 0; i < image->width; i++) {
6,255,180✔
330
            int alpha = pabyAlpha[i * rb.data.rgba.pixel_step];
6,240,300✔
331

332
            if (alpha == 0)
6,240,300✔
333
              pabyUPM[i] = 0;
2,345,718✔
334
            else {
335
              int result =
3,894,582✔
336
                  (pabyData[i * rb.data.rgba.pixel_step] * 255) / alpha;
3,894,582✔
337

338
              if (result > 255)
3,894,582✔
339
                result = 255;
340

341
              pabyUPM[i] = result;
3,894,582✔
342
            }
343
          }
344

345
          eErr = GDALRasterIO(hBand, GF_Write, 0, iLine, image->width, 1,
14,880✔
346
                              pabyUPM, image->width, 1, GDT_Byte, 1, 0);
347
          free(pabyUPM);
14,880✔
348
        }
349
      }
350
      if (eErr != CE_None) {
45,485✔
351
        msReleaseLock(TLOCK_GDAL);
×
352
        msSetError(MS_MISCERR, "GDALRasterIO() failed.\n", "msSaveImageGDAL()");
×
353
        GDALClose(hMemDS);
×
354
        msFree(filenameToFree);
×
355
        return MS_FAILURE;
×
356
      }
357
    }
358
  }
359

360
  /* -------------------------------------------------------------------- */
361
  /*      Attach the palette if appropriate.                              */
362
  /* -------------------------------------------------------------------- */
363
  if (format->imagemode == MS_IMAGEMODE_RGB) {
210✔
364
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 1), GCI_RedBand);
14✔
365
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 2),
14✔
366
                                     GCI_GreenBand);
367
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 3),
14✔
368
                                     GCI_BlueBand);
369
  } else if (format->imagemode == MS_IMAGEMODE_RGBA) {
196✔
370
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 1), GCI_RedBand);
18✔
371
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 2),
18✔
372
                                     GCI_GreenBand);
373
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 3),
18✔
374
                                     GCI_BlueBand);
375
    GDALSetRasterColorInterpretation(GDALGetRasterBand(hMemDS, 4),
18✔
376
                                     GCI_AlphaBand);
377
  }
378

379
  /* -------------------------------------------------------------------- */
380
  /*      Assign the projection and coordinate system to the memory       */
381
  /*      dataset.                                                        */
382
  /* -------------------------------------------------------------------- */
383

384
  if (map != NULL) {
210✔
385
    char *pszWKT;
386

387
    GDALSetGeoTransform(hMemDS, map->gt.geotransform);
209✔
388

389
    pszWKT = msProjectionObj2OGCWKT(&(map->projection));
209✔
390
    if (pszWKT != NULL) {
209✔
391
      GDALSetProjection(hMemDS, pszWKT);
182✔
392
      msFree(pszWKT);
182✔
393
    }
394
  }
395

396
  /* -------------------------------------------------------------------- */
397
  /*      Possibly assign a nodata value.                                 */
398
  /* -------------------------------------------------------------------- */
399
  const char *nullvalue = msGetOutputFormatOption(format, "NULLVALUE", NULL);
210✔
400
  if (nullvalue != NULL) {
210✔
401
    const double dfNullValue = atof(nullvalue);
402
    for (int iBand = 0; iBand < nBands; iBand++) {
48✔
403
      GDALRasterBandH hBand = GDALGetRasterBand(hMemDS, iBand + 1);
24✔
404
      GDALSetRasterNoDataValue(hBand, dfNullValue);
24✔
405
    }
406
  }
407

408
  /* -------------------------------------------------------------------- */
409
  /*  Try to save resolution in the output file.                          */
410
  /* -------------------------------------------------------------------- */
411
  if (image->resolution > 0) {
210✔
412
    char res[30];
413

414
    snprintf(res, sizeof(res), "%lf", image->resolution);
415
    GDALSetMetadataItem(hMemDS, "TIFFTAG_XRESOLUTION", res, NULL);
210✔
416
    GDALSetMetadataItem(hMemDS, "TIFFTAG_YRESOLUTION", res, NULL);
210✔
417
    GDALSetMetadataItem(hMemDS, "TIFFTAG_RESOLUTIONUNIT", "2", NULL);
210✔
418
  }
419

420
  /* -------------------------------------------------------------------- */
421
  /*      Separate creation options from metadata items.                  */
422
  /* -------------------------------------------------------------------- */
423
  std::vector<char *> apszCreationOptions;
210✔
424
  for (int i = 0; i < format->numformatoptions; i++) {
539✔
425
    char *option = format->formatoptions[i];
329✔
426

427
    // MDI stands for MetaDataItem
428
    if (STARTS_WITH(option, "mdi_")) {
329✔
429
      const char *option_without_band = option + strlen("mdi_");
70✔
430
      GDALMajorObjectH hObject = (GDALMajorObjectH)hMemDS;
431
      if (STARTS_WITH(option_without_band, "BAND_")) {
70✔
432
        int nBandNumber = atoi(option_without_band + strlen("BAND_"));
23✔
433
        if (nBandNumber > 0 && nBandNumber <= nBands) {
23✔
434
          const char *pszAfterBand =
435
              strchr(option_without_band + strlen("BAND_"), '_');
436
          if (pszAfterBand != NULL) {
23✔
437
            hObject = (GDALMajorObjectH)GDALGetRasterBand(hMemDS, nBandNumber);
23✔
438
            option_without_band = pszAfterBand + 1;
23✔
439
          }
440
        } else {
441
          msDebug("Invalid band number %d in metadata item option %s",
×
442
                  nBandNumber, option);
443
        }
444
      }
445
      if (hObject) {
70✔
446
        std::string osDomain(option_without_band);
70✔
447
        size_t nUnderscorePos = osDomain.find('_');
70✔
448
        if (nUnderscorePos != std::string::npos) {
70✔
449
          std::string osKeyValue = osDomain.substr(nUnderscorePos + 1);
70✔
450
          osDomain.resize(nUnderscorePos);
451
          if (osDomain == "default")
70✔
452
            osDomain.clear();
453
          size_t nEqualPos = osKeyValue.find('=');
70✔
454
          if (nEqualPos != std::string::npos) {
70✔
455
            GDALSetMetadataItem(
70✔
456
                hObject, osKeyValue.substr(0, nEqualPos).c_str(),
140✔
457
                osKeyValue.substr(nEqualPos + 1).c_str(), osDomain.c_str());
140✔
458
          }
459
        } else {
460
          msDebug("Invalid format in metadata item option %s", option);
×
461
        }
462
      }
463
    } else {
464
      apszCreationOptions.emplace_back(option);
259✔
465
    }
466
  }
467
  apszCreationOptions.emplace_back(nullptr);
210✔
468

469
  /* -------------------------------------------------------------------- */
470
  /*      Create a disk image in the selected output format from the      */
471
  /*      memory image.                                                   */
472
  /* -------------------------------------------------------------------- */
473
  hOutputDS = GDALCreateCopy(hOutputDriver, filename, hMemDS, FALSE,
210✔
474
                             &apszCreationOptions[0], NULL, NULL);
475

476
  if (hOutputDS == NULL) {
210✔
477
    GDALClose(hMemDS);
×
478
    msReleaseLock(TLOCK_GDAL);
×
479
    msSetError(MS_MISCERR, "Failed to create output %s file.\n%s",
×
480
               "msSaveImageGDAL()", format->driver + 5, CPLGetLastErrorMsg());
×
481
    msFree(filenameToFree);
×
482
    return MS_FAILURE;
×
483
  }
484

485
  /* closing the memory DS also frees all associated resources. */
486
  GDALClose(hMemDS);
210✔
487

488
  GDALClose(hOutputDS);
210✔
489
  msReleaseLock(TLOCK_GDAL);
210✔
490

491
  /* -------------------------------------------------------------------- */
492
  /*      Are we writing license info into the image?                     */
493
  /*      If so, add it to the temp file on disk now.                     */
494
  /* -------------------------------------------------------------------- */
495
#ifdef USE_EXEMPI
496
  if (bUseXmp == MS_TRUE) {
210✔
497
    if (msXmpWrite(map, filename) == MS_FAILURE) {
1✔
498
      /* Something bad happened. */
499
      msSetError(MS_MISCERR, "XMP write to %s failed.\n", "msSaveImageGDAL()",
×
500
                 filename);
501
      msFree(filenameToFree);
×
502
      return MS_FAILURE;
×
503
    }
504
  }
505
#endif
506

507
  /* -------------------------------------------------------------------- */
508
  /*      Is this supposed to be a temporary file?  If so, stream to      */
509
  /*      stdout and delete the file.                                     */
510
  /* -------------------------------------------------------------------- */
511
  if (bFileIsTemporary) {
210✔
512
    VSILFILE *fp;
513
    unsigned char block[4000];
514
    int bytes_read;
515

516
    if (msIO_needBinaryStdout() == MS_FAILURE) {
21✔
517
      msFree(filenameToFree);
×
518
      return MS_FAILURE;
×
519
    }
520

521
    /* We aren't sure how far back GDAL exports the VSI*L API, so
522
       we only use it if we suspect we need it.  But we do need it if
523
       holding temporary file in memory. */
524
    fp = VSIFOpenL(filename, "rb");
21✔
525
    if (fp == NULL) {
21✔
526
      msSetError(MS_MISCERR, "Failed to open %s for streaming to stdout.",
×
527
                 "msSaveImageGDAL()", filename);
528
      msFree(filenameToFree);
×
529
      return MS_FAILURE;
×
530
    }
531

532
    while ((bytes_read = VSIFReadL(block, 1, sizeof(block), fp)) > 0)
101✔
533
      msIO_fwrite(block, 1, bytes_read, stdout);
80✔
534

535
    VSIFCloseL(fp);
21✔
536

537
    VSIUnlink(filename);
21✔
538
    msCleanVSIDir("/vsimem/msout");
21✔
539
  }
540
  msFree(filenameToFree);
210✔
541

542
  return MS_SUCCESS;
210✔
543
}
544

545
/************************************************************************/
546
/*                       msInitGDALOutputFormat()                       */
547
/************************************************************************/
548

549
int msInitDefaultGDALOutputFormat(outputFormatObj *format)
1,144✔
550

551
{
552
  GDALDriverH hDriver;
553

554
  msGDALInitialize();
1,144✔
555

556
  /* -------------------------------------------------------------------- */
557
  /*      check that this driver exists.  Note visiting drivers should    */
558
  /*      be pretty threadsafe so don't bother acquiring the GDAL         */
559
  /*      lock.                                                           */
560
  /* -------------------------------------------------------------------- */
561
  hDriver = GDALGetDriverByName(format->driver + 5);
1,144✔
562
  if (hDriver == NULL) {
1,144✔
563
    msSetError(MS_MISCERR, "No GDAL driver named `%s' available.",
×
564
               "msInitGDALOutputFormat()", format->driver + 5);
×
565
    return MS_FAILURE;
×
566
  }
567

568
  if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, NULL) == NULL &&
1,466✔
569
      GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, NULL) == NULL) {
322✔
570
    msSetError(MS_MISCERR, "GDAL `%s' driver does not support output.",
×
571
               "msInitGDALOutputFormat()", format->driver + 5);
×
572
    return MS_FAILURE;
×
573
  }
574

575
  /* -------------------------------------------------------------------- */
576
  /*      Initialize the object.                                          */
577
  /* -------------------------------------------------------------------- */
578
  format->imagemode = MS_IMAGEMODE_RGB;
1,144✔
579
  format->renderer = MS_RENDER_WITH_AGG;
1,144✔
580

581
  if (GDALGetMetadataItem(hDriver, GDAL_DMD_MIMETYPE, NULL) != NULL)
1,144✔
582
    format->mimetype =
876✔
583
        msStrdup(GDALGetMetadataItem(hDriver, GDAL_DMD_MIMETYPE, NULL));
876✔
584
  if (GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSION, NULL) != NULL)
1,144✔
585
    format->extension =
1,138✔
586
        msStrdup(GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSION, NULL));
1,138✔
587

588
  return MS_SUCCESS;
589
}
590

591
char **msGetStringListFromHashTable(hashTableObj *table) {
1,984✔
592
  struct hashObj *tp = NULL;
593
  int i;
594
  char **papszRet = NULL;
595

596
  if (!table)
1,984✔
597
    return NULL;
598
  if (msHashIsEmpty(table))
1,984✔
599
    return NULL;
600

601
  for (i = 0; i < MS_HASHSIZE; ++i) {
252✔
602
    if (table->items[i] != NULL) {
246✔
603
      for (tp = table->items[i]; tp != NULL; tp = tp->next) {
12✔
604
        papszRet = CSLSetNameValue(papszRet, tp->key, tp->data);
6✔
605
      }
606
    }
607
  }
608
  return papszRet;
609
}
610

611
/************************************************************************/
612
/*                      msProjectionObj2OGCWKT()                        */
613
/*                                                                      */
614
/*      We stick to the C API for OGRSpatialReference object access     */
615
/*      to allow MapServer+GDAL to be built without C++                 */
616
/*      complications.                                                  */
617
/*                                                                      */
618
/*      Note that this function will return NULL on failure, and the    */
619
/*      returned string should be freed with msFree().                  */
620
/************************************************************************/
621

622
char *msProjectionObj2OGCWKT(projectionObj *projection)
258✔
623

624
{
625
  OGRSpatialReferenceH hSRS;
626
  char *pszWKT = NULL, *pszProj4, *pszInitEpsg = NULL;
258✔
627
  int nLength = 0, i;
628
  OGRErr eErr;
629

630
  if (projection->proj == NULL)
258✔
631
    return NULL;
632

633
  hSRS = OSRNewSpatialReference(NULL);
216✔
634
  /* -------------------------------------------------------------------- */
635
  /*      Look for an EPSG-like projection argument                       */
636
  /* -------------------------------------------------------------------- */
637
  if ((projection->numargs == 1 ||
31✔
638
       (projection->numargs == 2 &&
25✔
639
        strstr(projection->args[1], "epsgaxis=") != NULL)) &&
241✔
640
      (pszInitEpsg = strcasestr(projection->args[0], "init=epsg:"))) {
210✔
641
    const int nEpsgCode = atoi(pszInitEpsg + strlen("init=epsg:"));
210✔
642
    eErr = OSRImportFromEPSG(hSRS, nEpsgCode);
210✔
643
    if (eErr != OGRERR_NONE) {
210✔
644
      // In case this is a pseudo EPSG code only defined in a text 'epsg'
645
      // file and not in proj.db
NEW
646
      eErr = OSRSetFromUserInput(
×
NEW
647
          hSRS, std::string("+").append(projection->args[0]).c_str());
×
648
    }
649
  } else {
650
    /* -------------------------------------------------------------------- */
651
    /*      Form arguments into a full Proj.4 definition string.            */
652
    /* -------------------------------------------------------------------- */
653
    for (i = 0; i < projection->numargs; i++)
24✔
654
      nLength += strlen(projection->args[i]) + 2;
18✔
655

656
    pszProj4 = (char *)CPLMalloc(nLength + 2);
6✔
657
    pszProj4[0] = '\0';
6✔
658

659
    for (i = 0; i < projection->numargs; i++) {
24✔
660
      strcat(pszProj4, "+");
661
      strcat(pszProj4, projection->args[i]);
18✔
662
      strcat(pszProj4, " ");
663
    }
664

665
    /* -------------------------------------------------------------------- */
666
    /*      Ingest the string into OGRSpatialReference.                     */
667
    /* -------------------------------------------------------------------- */
668
    eErr = OSRImportFromProj4(hSRS, pszProj4);
6✔
669
    CPLFree(pszProj4);
6✔
670
  }
671

672
  /* -------------------------------------------------------------------- */
673
  /*      Export as a WKT string.                                         */
674
  /* -------------------------------------------------------------------- */
675
  if (eErr == OGRERR_NONE)
6✔
676
    OSRExportToWkt(hSRS, &pszWKT);
216✔
677

678
  OSRDestroySpatialReference(hSRS);
216✔
679

680
  if (pszWKT) {
216✔
681
    char *pszWKT2 = msStrdup(pszWKT);
216✔
682
    CPLFree(pszWKT);
216✔
683

684
    return pszWKT2;
216✔
685
  } else
686
    return NULL;
687
}
688

689
/************************************************************************/
690
/*                    msGDALDriverSupportsVirtualIOOutput()             */
691
/************************************************************************/
692

693
int msGDALDriverSupportsVirtualIOOutput(GDALDriverH hDriver) {
178✔
694
  /* We need special testing here for the netCDF driver, since recent */
695
  /* GDAL versions advertise VirtualIO support, but this is only for the */
696
  /* read-side of the driver, not the write-side. */
697
  return GDALGetMetadataItem(hDriver, GDAL_DCAP_VIRTUALIO, NULL) != NULL &&
178✔
698
         !EQUAL(GDALGetDescription(hDriver), "netCDF");
171✔
699
}
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

© 2026 Coveralls, Inc