Coverage Report

Created: 2026-03-30 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/mrf/mrf_util.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2002-2012, California Institute of Technology.
3
 * All rights reserved.  Based on Government Sponsored Research under contracts
4
 * NAS7-1407 and/or NAS7-03001.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *   1. Redistributions of source code must retain the above copyright notice,
9
 * this list of conditions and the following disclaimer.
10
 *   2. Redistributions in binary form must reproduce the above copyright
11
 * notice, this list of conditions and the following disclaimer in the
12
 * documentation and/or other materials provided with the distribution.
13
 *   3. Neither the name of the California Institute of Technology (Caltech),
14
 * its operating division the Jet Propulsion Laboratory (JPL), the National
15
 * Aeronautics and Space Administration (NASA), nor the names of its
16
 * contributors may be used to endorse or promote products derived from this
17
 * software without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED. IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE
23
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 *
31
 * Copyright 2014-2021 Esri
32
 *
33
 * Licensed under the Apache License, Version 2.0 (the "License");
34
 * you may not use this file except in compliance with the License.
35
 * You may obtain a copy of the License at
36
 *
37
 * http://www.apache.org/licenses/LICENSE-2.0
38
 *
39
 * Unless required by applicable law or agreed to in writing, software
40
 * distributed under the License is distributed on an "AS IS" BASIS,
41
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42
 * See the License for the specific language governing permissions and
43
 * limitations under the License.
44
 *
45
 *  Functions used by the driver, should have prototypes in the header file
46
 *
47
 *  Author: Lucian Plesea
48
 */
49
50
#include "marfa.h"
51
#include <zlib.h>
52
#include <algorithm>
53
#include <limits>
54
#include "mrfdrivercore.h"
55
#include "gdal_frmts.h"
56
57
// LERC and QB3 only work on little endian machines
58
#if defined(WORDS_BIGENDIAN)
59
#undef LERC
60
#undef QB3_SUPPORT
61
#endif
62
63
NAMESPACE_MRF_START
64
65
// These have to be positionally in sync with the enums in marfa.h
66
static const char *const ILC_N[] = {
67
#ifdef HAVE_PNG
68
    "PNG",    "PPNG",
69
#endif
70
#ifdef HAVE_JPEG
71
    "JPEG",
72
#endif
73
#if defined(HAVE_PNG) && defined(HAVE_JPEG)
74
    "JPNG",
75
#endif
76
    "NONE",   "DEFLATE", "TIF",
77
#if defined(LERC)
78
    "LERC",
79
#endif
80
#if defined(ZSTD_SUPPORT)
81
    "ZSTD",
82
#endif
83
#if defined(QB3_SUPPORT)
84
    "QB3",
85
#endif
86
    "Unknown"};
87
88
static const char *const ILC_E[] = {
89
#ifdef HAVE_PNG
90
    ".ppg", ".ppg",
91
#endif
92
#ifdef HAVE_JPEG
93
    ".pjg",
94
#endif
95
#if defined(HAVE_PNG) && defined(HAVE_JPEG)
96
    ".pjp",
97
#endif
98
    ".til", ".pzp", ".ptf",
99
#if defined(LERC)
100
    ".lrc",
101
#endif
102
#if defined(ZSTD_SUPPORT)
103
    ".pzs",
104
#endif
105
#if defined(QB3_SUPPORT)
106
    ".pq3",
107
#endif
108
    ""};
109
110
static const char *const ILO_N[] = {"PIXEL", "BAND", "LINE", "Unknown"};
111
112
char const *const *ILComp_Name = ILC_N;
113
char const *const *ILComp_Ext = ILC_E;
114
char const *const *ILOrder_Name = ILO_N;
115
116
/**
117
 *  Get the string for a compression type
118
 */
119
const char *CompName(ILCompression comp)
120
15.4k
{
121
15.4k
    if (comp >= IL_ERR_COMP)
122
0
        return ILComp_Name[IL_ERR_COMP];
123
15.4k
    return ILComp_Name[comp];
124
15.4k
}
125
126
/**
127
 *  Get the string for an order type
128
 */
129
const char *OrderName(ILOrder val)
130
11.7k
{
131
11.7k
    if (val >= IL_ERR_ORD)
132
0
        return ILOrder_Name[IL_ERR_ORD];
133
11.7k
    return ILOrder_Name[val];
134
11.7k
}
135
136
ILCompression CompToken(const char *opt, ILCompression def)
137
11.7k
{
138
11.7k
    int i;
139
11.7k
    if (nullptr == opt)
140
0
        return def;
141
48.6k
    for (i = 0; ILCompression(i) < IL_ERR_COMP; i++)
142
48.6k
        if (EQUAL(opt, ILComp_Name[i]))
143
11.7k
            break;
144
11.7k
    if (IL_ERR_COMP == ILCompression(i))
145
6
        return def;
146
11.7k
    return ILCompression(i);
147
11.7k
}
148
149
/**
150
 *  Find a compression token
151
 */
152
ILOrder OrderToken(const char *opt, ILOrder def)
153
11.7k
{
154
11.7k
    int i;
155
11.7k
    if (nullptr == opt)
156
0
        return def;
157
11.9k
    for (i = 0; ILOrder(i) < IL_ERR_ORD; i++)
158
11.9k
        if (EQUAL(opt, ILOrder_Name[i]))
159
11.7k
            break;
160
11.7k
    if (IL_ERR_ORD == ILOrder(i))
161
0
        return def;
162
11.7k
    return ILOrder(i);
163
11.7k
}
164
165
//
166
//  Inserters for ILSize and ILIdx types
167
//
168
std::ostream &operator<<(std::ostream &out, const ILSize &sz)
169
0
{
170
0
    out << "X=" << sz.x << ",Y=" << sz.y << ",Z=" << sz.z << ",C=" << sz.c
171
0
        << ",L=" << sz.l;
172
0
    return out;
173
0
}
174
175
std::ostream &operator<<(std::ostream &out, const ILIdx &t)
176
0
{
177
0
    out << "offset=" << t.offset << ",size=" << t.size;
178
0
    return out;
179
0
}
180
181
// Define PPMW to enable this handy debug function
182
#ifdef PPMW
183
void ppmWrite(const char *fname, const char *data, const ILSize &sz)
184
{
185
    FILE *fp = fopen(fname, "wb");
186
    switch (sz.c)
187
    {
188
        case 4:  // Strip the alpha
189
            fprintf(fp, "P6 %d %d 255\n", sz.x, sz.y);
190
            {
191
                char *d = (char *)data;
192
                for (int i = sz.x * sz.y; i; i--)
193
                {
194
                    fwrite(d, 3, 1, fp);
195
                    d += 4;
196
                }
197
            }
198
            break;
199
        case 3:
200
            fprintf(fp, "P6 %d %d 255\n", sz.x, sz.y);
201
            fwrite(data, sz.x * sz.y, 3, fp);
202
            break;
203
        case 1:
204
            fprintf(fp, "P5 %d %d 255\n", sz.x, sz.y);
205
            fwrite(data, sz.x, sz.y, fp);
206
            break;
207
        default:
208
            fprintf(stderr, "Can't write ppm file with %d bands\n", /*ok*/
209
                    sz.c);
210
    }
211
    fclose(fp);
212
    return;
213
}
214
#endif
215
216
// Returns the size of the index for image and overlays
217
// If scale is zero, only base image
218
GIntBig IdxSize(const ILImage &full, const int scale)
219
11.6k
{
220
11.6k
    ILImage img = full;
221
11.6k
    img.pagecount = pcount(img.size, img.pagesize);
222
11.6k
    GIntBig sz = img.pagecount.l;
223
11.6k
    while (scale != 0 && 1 != img.pagecount.x * img.pagecount.y)
224
0
    {
225
0
        img.size.x = pcount(img.size.x, scale);
226
0
        img.size.y = pcount(img.size.y, scale);
227
0
        img.pagecount = pcount(img.size, img.pagesize);
228
0
        sz += img.pagecount.l;
229
0
    }
230
231
11.6k
    if (sz >
232
11.6k
        std::numeric_limits<GIntBig>::max() / static_cast<int>(sizeof(ILIdx)))
233
0
    {
234
0
        CPLError(CE_Failure, CPLE_AppDefined, "IdxSize: integer overflow");
235
0
        return 0;
236
0
    }
237
11.6k
    return sz * sizeof(ILIdx);
238
11.6k
}
239
240
ILImage::ILImage()
241
23.7k
    : dataoffset(0), idxoffset(0), quality(85), pageSizeBytes(0),
242
23.7k
      size(ILSize(1, 1, 1, 1, 0)), pagesize(ILSize(384, 384, 1, 1, 0)),
243
23.7k
      pagecount(pcount(size, pagesize)),
244
#ifdef HAVE_PNG
245
23.7k
      comp(IL_PNG),
246
#else
247
      comp(IL_NONE),
248
#endif
249
23.7k
      order(IL_Interleaved), nbo(false), hasNoData(FALSE), NoDataValue(0.0),
250
23.7k
      dt(GDT_Unknown), ci(GCI_Undefined)
251
23.7k
{
252
23.7k
}
253
254
/**
255
 *\brief Get a file name by replacing the extension.
256
 * pass the data file name and the default extension starting with .
257
 * If name length is not sufficient, it returns the extension
258
 * If the input name is curl with parameters, the base file extension gets
259
 *changed and parameters are preserved.
260
 */
261
262
CPLString getFname(const CPLString &in, const char *ext)
263
16.2k
{
264
16.2k
    if (strlen(in) < strlen(ext))
265
0
        return CPLString(ext);
266
267
16.2k
    CPLString ret(in);
268
    // Is it a web file with parameters?
269
16.2k
    size_t extlen = strlen(ext);
270
16.2k
    size_t qmark = ret.find_first_of('?');
271
16.2k
    if (!(qmark != std::string::npos && 0 == in.find("/vsicurl/http") &&
272
0
          qmark >= extlen))
273
16.2k
        qmark = ret.size();
274
16.2k
    return ret.replace(qmark - extlen, extlen, ext);
275
16.2k
}
276
277
/**
278
 *\brief Get a file name, either from the configuration or from the default file
279
 *name If the token is not defined by CPLGetXMLValue, if the extension of the in
280
 *name is .xml, it returns the token with the extension changed to defext.
281
 * Otherwise it returns the token itself
282
 * It is pretty hard to separate local vs remote due to the gdal file name
283
 *ornaments Absolute file names start with: ?:/ or /
284
 *
285
 */
286
287
CPLString getFname(CPLXMLNode *node, const char *token, const CPLString &in,
288
                   const char *def)
289
23.4k
{
290
23.4k
    CPLString fn = CPLGetXMLValue(node, token, "");
291
23.4k
    if (fn.empty())  // Not provided
292
16.2k
        return getFname(in, def);
293
7.19k
    size_t slashPos = fn.find_first_of("\\/");
294
295
    // Does it look like an absolute path or we won't find the basename of 'in'
296
7.19k
    if (slashPos == 0                       // Starts with slash
297
3.59k
        || (slashPos == 2 && fn[1] == ':')  // Starts with disk letter column
298
        // Does not start with dots then slash
299
3.59k
        || (slashPos != fn.npos && slashPos != fn.find_first_not_of('.')) ||
300
3.59k
        EQUALN(in, "<MRF_META>", 10)  // XML string input
301
3.59k
        || in.find_first_of("\\/") ==
302
3.59k
               in.npos)  // We can't get a basename from 'in'
303
3.59k
        return fn;
304
305
    // Relative path, prepend the path from the in file name
306
3.59k
    return in.substr(0, in.find_last_of("\\/") + 1) + fn;
307
7.19k
}
308
309
/**
310
 *\brief Extracts a numerical value from a XML node
311
 * It works like CPLGetXMLValue except for the default value being
312
 * a number instead of a string
313
 */
314
315
double getXMLNum(CPLXMLNode *node, const char *pszPath, double def)
316
84.4k
{
317
84.4k
    const char *textval = CPLGetXMLValue(node, pszPath, nullptr);
318
84.4k
    if (textval)
319
43.0k
        return atof(textval);
320
41.4k
    return def;
321
84.4k
}
322
323
//
324
// Calculate offset of index, pos is in pages
325
//
326
327
GIntBig IdxOffset(const ILSize &pos, const ILImage &img)
328
120k
{
329
120k
    return img.idxoffset +
330
120k
           sizeof(ILIdx) *
331
120k
               (pos.c +
332
120k
                img.pagecount.c *
333
120k
                    (pos.x + img.pagecount.x *
334
120k
                                 (pos.y + img.pagecount.y *
335
120k
                                              static_cast<GIntBig>(pos.z))));
336
120k
}
337
338
// Is compression type endianness dependent?
339
bool is_Endianness_Dependent(GDALDataType dt, ILCompression comp)
340
66.7k
{
341
    // Add here all endianness dependent compressions
342
66.7k
    if (IL_ZLIB == comp || IL_NONE == comp)
343
13.8k
        if (GDALGetDataTypeSizeBytes(dt) > 1)
344
0
            return true;
345
66.7k
    return false;
346
66.7k
}
347
348
MRFRasterBand *newMRFRasterBand(MRFDataset *pDS, const ILImage &image, int b,
349
                                int level)
350
2.71M
{
351
2.71M
    MRFRasterBand *bnd = nullptr;
352
2.71M
    CPLErrorReset();
353
2.71M
    switch (pDS->current.comp)
354
2.71M
    {
355
0
#ifdef HAVE_PNG
356
0
        case IL_PPNG:  // Uses the PNG code, just has a palette in each PNG
357
6.55k
        case IL_PNG:
358
6.55k
            bnd = new PNG_Band(pDS, image, b, level);
359
6.55k
            break;
360
0
#endif
361
0
#ifdef HAVE_JPEG
362
6.33k
        case IL_JPEG:
363
6.33k
            bnd = new JPEG_Band(pDS, image, b, level);
364
6.33k
            break;
365
0
#endif
366
0
#if defined(HAVE_PNG) && defined(HAVE_JPEG)
367
0
        case IL_JPNG:
368
0
            bnd = new JPNG_Band(pDS, image, b, level);
369
0
            break;
370
0
#endif
371
556
        case IL_NONE:
372
556
            bnd = new Raw_Band(pDS, image, b, level);
373
556
            break;
374
0
#if defined(LERC)
375
2.68M
        case IL_LERC:
376
2.68M
            bnd = new LERC_Band(pDS, image, b, level);
377
2.68M
            break;
378
0
#endif
379
#if defined(QB3_SUPPORT)
380
        case IL_QB3:
381
            bnd = new QB3_Band(pDS, image, b, level);
382
            break;
383
#endif
384
        // ZLIB is just raw + deflate
385
683
        case IL_ZLIB:
386
683
            bnd = new Raw_Band(pDS, image, b, level);
387
683
            bnd->SetDeflate(1);
388
683
            break;
389
            // Same for ZSTD
390
0
#if defined(ZSTD_SUPPORT)
391
0
        case IL_ZSTD:
392
0
            bnd = new Raw_Band(pDS, image, b, level);
393
0
            bnd->SetZstd(1);
394
0
            break;
395
0
#endif
396
11.6k
        case IL_TIF:
397
11.6k
            if (image.pageSizeBytes > INT_MAX - 1024)
398
0
                return nullptr;
399
11.6k
            bnd = new TIF_Band(pDS, image, b, level);
400
11.6k
            break;
401
0
        default:
402
0
            CPLError(CE_Failure, CPLE_AssertionFailed,
403
0
                     "Unsupported MRF compression");
404
0
            return nullptr;
405
2.71M
    }
406
407
    // If something was flagged during band creation
408
2.71M
    if (CPLGetLastErrorNo() != CE_None)
409
49
    {
410
49
        delete bnd;
411
49
        return nullptr;
412
49
    }
413
414
    // Copy the RW mode from the dataset
415
2.71M
    bnd->SetAccess(pDS->eAccess);
416
2.71M
    return bnd;
417
2.71M
}
418
419
/**
420
 *\brief log in a given base
421
 */
422
double logbase(double val, double base)
423
0
{
424
0
    return log(val) / log(base);
425
0
}
426
427
/**
428
 *\brief Is logbase(val, base) an integer?
429
 *
430
 */
431
int IsPower(double value, double base)
432
0
{
433
0
    double v = logbase(value, base);
434
0
    return CPLIsEqual(v, int(v + 0.5));
435
0
}
436
437
/************************************************************************/
438
/*                         SearchXMLSiblings()                          */
439
/************************************************************************/
440
441
/**
442
 *\brief Search for a sibling of the root node with a given name.
443
 *
444
 * Searches only the next siblings of the node passed in for the named element
445
 *or attribute. If the first character of the pszElement is '=', the search
446
 *includes the psRoot node
447
 *
448
 * @param psRoot the root node to search.  This should be a node of type
449
 * CXT_Element.  NULL is safe.
450
 *
451
 * @param pszElement the name of the element or attribute to search for.
452
 *
453
 * @return The first matching node or NULL on failure.
454
 */
455
456
CPLXMLNode *SearchXMLSiblings(CPLXMLNode *psRoot, const char *pszElement)
457
0
{
458
0
    if (psRoot == nullptr || pszElement == nullptr)
459
0
        return nullptr;
460
461
    // If the strings starts with '=', skip it and test the root
462
    // If not, start testing with the next sibling
463
0
    if (pszElement[0] == '=')
464
0
        pszElement++;
465
0
    else
466
0
        psRoot = psRoot->psNext;
467
468
0
    for (; psRoot != nullptr; psRoot = psRoot->psNext)
469
0
        if ((psRoot->eType == CXT_Element || psRoot->eType == CXT_Attribute) &&
470
0
            EQUAL(pszElement, psRoot->pszValue))
471
0
            return psRoot;
472
0
    return nullptr;
473
0
}
474
475
//
476
// Print a double so it can be read with strod while preserving precision
477
// Unfortunately this is not quite possible or portable enough at this time
478
//
479
CPLString PrintDouble(double d, const char *frmt)
480
22.2k
{
481
22.2k
    CPLString res;
482
22.2k
    res.FormatC(d, nullptr);
483
22.2k
    if (CPLStrtod(res.c_str(), nullptr) == d)
484
21.8k
        return res;
485
486
    //  This would be the right code with a C99 compiler that supports %a
487
    //  readback in strod()
488
    //    return CPLString().Printf("%a",d);
489
490
346
    return CPLString().FormatC(d, frmt);
491
22.2k
}
492
493
void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
494
                        const char *pszVal)
495
22.2k
{
496
22.2k
    CPLCreateXMLNode(parent, CXT_Attribute, pszName);
497
22.2k
    CPLSetXMLValue(parent, pszName, pszVal);
498
22.2k
}
499
500
void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
501
                        const double val, const char *frmt)
502
22.2k
{
503
22.2k
    XMLSetAttributeVal(parent, pszName, PrintDouble(val, frmt));
504
22.2k
}
505
506
CPLXMLNode *XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
507
                               const ILSize &sz, const char *frmt)
508
7.41k
{
509
7.41k
    CPLXMLNode *node = CPLCreateXMLNode(parent, CXT_Element, pszName);
510
7.41k
    XMLSetAttributeVal(node, "x", sz.x, frmt);
511
7.41k
    XMLSetAttributeVal(node, "y", sz.y, frmt);
512
7.41k
    if (sz.z != 1)
513
0
        XMLSetAttributeVal(node, "z", sz.z, frmt);
514
7.41k
    XMLSetAttributeVal(node, "c", sz.c, frmt);
515
7.41k
    return node;
516
7.41k
}
517
518
//
519
// Prints a vector of doubles into a string and sets that string as the value of
520
// an XML attribute If all values are the same, it only prints one
521
//
522
void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
523
                        std::vector<double> const &values)
524
0
{
525
0
    if (values.empty())
526
0
        return;
527
528
0
    CPLString value;
529
0
    double val = values[0];
530
0
    int single_val = true;
531
0
    for (int i = 0; i < int(values.size()); i++)
532
0
    {
533
0
        if (val != values[i])
534
0
            single_val = false;
535
0
        value.append(PrintDouble(values[i]) + " ");
536
0
    }
537
0
    value.pop_back();  // Cut the last space
538
0
    if (single_val)
539
0
        value = PrintDouble(values[0]);
540
0
    CPLCreateXMLNode(parent, CXT_Attribute, pszName);
541
0
    CPLSetXMLValue(parent, pszName, value);
542
0
}
543
544
/**
545
 *\brief Verify or make a file that big
546
 *
547
 * @return true if size is OK or if extend succeeded
548
 */
549
550
int CheckFileSize(const char *fname, GIntBig sz, GDALAccess eAccess)
551
0
{
552
553
0
    VSIStatBufL statb;
554
0
    if (VSIStatL(fname, &statb))
555
0
        return false;
556
0
    if (statb.st_size >= sz)
557
0
        return true;
558
559
    // Don't change anything unless updating
560
0
    if (eAccess != GA_Update)
561
0
        return false;
562
563
    // There is no ftruncate in VSI, only truncate()
564
0
    VSILFILE *ifp = VSIFOpenL(fname, "r+b");
565
0
    if (ifp == nullptr)
566
0
        return false;
567
568
0
    int ret = VSIFTruncateL(ifp, sz);
569
0
    VSIFCloseL(ifp);
570
0
    return !ret;
571
0
}
572
573
NAMESPACE_MRF_END
574
575
/************************************************************************/
576
/*                          GDALRegister_MRF()                          */
577
/************************************************************************/
578
579
USING_NAMESPACE_MRF
580
581
void GDALRegister_MRF()
582
24
{
583
24
    if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
584
0
        return;
585
586
24
    GDALDriver *driver = new GDALDriver();
587
24
    MRFDriverSetCommonMetadata(driver);
588
589
24
    driver->SetMetadataItem(
590
24
        GDAL_DMD_CREATIONOPTIONLIST,
591
24
        "<CreationOptionList>"
592
24
        "   <Option name='COMPRESS' type='string-select' "
593
24
#ifdef HAVE_PNG
594
24
        "default='PNG' description='PPNG = Palette PNG; DEFLATE = zlib '>"
595
#else
596
        "default='NONE' description='DEFLATE = zlib '>"
597
#endif
598
24
#ifdef HAVE_JPEG
599
24
        "       <Value>JPEG</Value>"
600
24
#endif
601
24
#ifdef HAVE_PNG
602
24
        "       <Value>PNG</Value>"
603
24
        "       <Value>PPNG</Value>"
604
24
#endif
605
24
#if defined(HAVE_JPEG) && defined(HAVE_PNG)
606
24
        "       <Value>JPNG</Value>"
607
24
#endif
608
24
        "       <Value>TIF</Value>"
609
24
        "       <Value>DEFLATE</Value>"
610
24
        "       <Value>NONE</Value>"
611
24
#if defined(LERC)
612
24
        "       <Value>LERC</Value>"
613
24
#endif
614
24
#if defined(ZSTD_SUPPORT)
615
24
        "       <Value>ZSTD</Value>"
616
24
#endif
617
#if defined(QB3_SUPPORT)
618
        "       <Value>QB3</Value>"
619
#endif
620
24
        "   </Option>"
621
24
        "   <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
622
24
        "       <Value>PIXEL</Value>"
623
24
        "       <Value>BAND</Value>"
624
24
        "   </Option>\n"
625
24
        "   <Option name='ZSIZE' type='int' description='Third dimension size' "
626
24
        "default='1'/>"
627
24
        "   <Option name='QUALITY' type='int' description='Compression "
628
24
        "dependent control value, for JPEG best=99, bad=0, default=85'/>\n"
629
24
        "   <Option name='BLOCKSIZE' type='int' description='Block size, both "
630
24
        "x and y, default 512'/>\n"
631
24
        "   <Option name='BLOCKXSIZE' type='int' description='Block x size, "
632
24
        "default=512'/>\n"
633
24
        "   <Option name='BLOCKYSIZE' type='int' description='Block y size, "
634
24
        "default=512'/>\n"
635
24
        "   <Option name='NETBYTEORDER' type='boolean' "
636
24
        "description='Force endian for certain compress options, default is "
637
24
        "host order'/>\n"
638
24
        "   <Option name='CACHEDSOURCE' type='string' "
639
24
        "description='The source raster, if this is a cache'/>\n"
640
24
        "   <Option name='UNIFORM_SCALE' type='int' description='Scale of "
641
24
        "overlays in MRF, usually 2'/>\n"
642
24
        "   <Option name='NOCOPY' type='boolean' description='Leave created "
643
24
        "MRF empty, default=no'/>\n"
644
24
        "   <Option name='DATANAME' type='string' description='Data file "
645
24
        "name'/>\n"
646
24
        "   <Option name='INDEXNAME' type='string' description='Index file "
647
24
        "name'/>\n"
648
24
        "   <Option name='SPACING' type='int' "
649
24
        "description='Leave this many unused bytes before each tile, "
650
24
        "default=0'/>\n"
651
24
        "   <Option name='PHOTOMETRIC' type='string-select' default='DEFAULT' "
652
24
        "description='Band interpretation, may affect block encoding'>\n"
653
24
        "       <Value>MULTISPECTRAL</Value>"
654
24
        "       <Value>RGB</Value>"
655
24
        "       <Value>YCC</Value>"
656
24
        "   </Option>\n"
657
24
        "   <Option name='OPTIONS' type='string' description='\n"
658
24
        "     Compression dependent parameters, space separated:\n"
659
24
#if defined(ZSTD_SUPPORT)
660
24
        "       ZSTD - boolean, enable libzstd as final stage, preferred over "
661
24
        "DEFLATE\n"
662
24
#endif
663
24
        "       DEFLATE - boolean, enable zlib as final stage\n"
664
24
        "       GZ - boolean, for DEFLATE enable gzip headers instead of zlib "
665
24
        "ones when using zlib\n"
666
24
        "       RAWZ - boolean, for DEFLATE disable all zlib headers\n"
667
24
        "       Z_STRATEGY - Z_HUFFMAN_ONLY | Z_FILTERED | Z_RLE | Z_FIXED: "
668
24
        "restricts DEFLATE and PNG strategy\n"
669
24
#if defined(LERC)
670
24
        "       LERC_PREC - numeric, set LERC precision, defaults to 0.5 for "
671
24
        "int and 0.001 for float\n"
672
24
        "       V1 - boolean, use LERC V1 (older) format\n"
673
24
        "       L2_VER - numeric, encode specific version of Lerc, default is "
674
24
        "library default\n"
675
24
        "                except for single band or INTERLEAVE=BAND, when it "
676
24
        "defaults to 2\n"
677
24
#endif
678
24
        "       OPTIMIZE - boolean, for JPEG, enables Huffman table "
679
24
        "optimization\n"
680
#if defined(BRUNSLI)
681
        "       JFIF - boolean, for JPEG, disable brunsli encoding\n"
682
#endif
683
24
        "'/>"
684
24
        "</CreationOptionList>\n");
685
686
24
    driver->pfnOpen = MRFDataset::Open;
687
24
    driver->pfnCreateCopy = MRFDataset::CreateCopy;
688
24
    driver->pfnCreate = MRFDataset::Create;
689
24
    driver->pfnDelete = MRFDataset::Delete;
690
24
    GetGDALDriverManager()->RegisterDriver(driver);
691
24
}