LCOV - code coverage report
Current view: top level - frmts/mrf - mrf_util.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 180 210 85.7 %
Date: 2025-10-24 00:53:13 Functions: 22 24 91.7 %

          Line data    Source code
       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         567 : const char *CompName(ILCompression comp)
     120             : {
     121         567 :     if (comp >= IL_ERR_COMP)
     122           0 :         return ILComp_Name[IL_ERR_COMP];
     123         567 :     return ILComp_Name[comp];
     124             : }
     125             : 
     126             : /**
     127             :  *  Get the string for an order type
     128             :  */
     129         367 : const char *OrderName(ILOrder val)
     130             : {
     131         367 :     if (val >= IL_ERR_ORD)
     132           0 :         return ILOrder_Name[IL_ERR_ORD];
     133         367 :     return ILOrder_Name[val];
     134             : }
     135             : 
     136         463 : ILCompression CompToken(const char *opt, ILCompression def)
     137             : {
     138             :     int i;
     139         463 :     if (nullptr == opt)
     140           0 :         return def;
     141        2458 :     for (i = 0; ILCompression(i) < IL_ERR_COMP; i++)
     142        2458 :         if (EQUAL(opt, ILComp_Name[i]))
     143         463 :             break;
     144         463 :     if (IL_ERR_COMP == ILCompression(i))
     145           0 :         return def;
     146         463 :     return ILCompression(i);
     147             : }
     148             : 
     149             : /**
     150             :  *  Find a compression token
     151             :  */
     152         496 : ILOrder OrderToken(const char *opt, ILOrder def)
     153             : {
     154             :     int i;
     155         496 :     if (nullptr == opt)
     156           0 :         return def;
     157         638 :     for (i = 0; ILOrder(i) < IL_ERR_ORD; i++)
     158         638 :         if (EQUAL(opt, ILOrder_Name[i]))
     159         496 :             break;
     160         496 :     if (IL_ERR_ORD == ILOrder(i))
     161           0 :         return def;
     162         496 :     return ILOrder(i);
     163             : }
     164             : 
     165             : //
     166             : //  Inserters for ILSize and ILIdx types
     167             : //
     168           0 : std::ostream &operator<<(std::ostream &out, const ILSize &sz)
     169             : {
     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             : }
     174             : 
     175           0 : std::ostream &operator<<(std::ostream &out, const ILIdx &t)
     176             : {
     177           0 :     out << "offset=" << t.offset << ",size=" << t.size;
     178           0 :     return out;
     179             : }
     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         314 : GIntBig IdxSize(const ILImage &full, const int scale)
     219             : {
     220         628 :     ILImage img = full;
     221         314 :     img.pagecount = pcount(img.size, img.pagesize);
     222         314 :     GIntBig sz = img.pagecount.l;
     223         353 :     while (scale != 0 && 1 != img.pagecount.x * img.pagecount.y)
     224             :     {
     225          39 :         img.size.x = pcount(img.size.x, scale);
     226          39 :         img.size.y = pcount(img.size.y, scale);
     227          39 :         img.pagecount = pcount(img.size, img.pagesize);
     228          39 :         sz += img.pagecount.l;
     229             :     }
     230             : 
     231         314 :     if (sz >
     232         314 :         std::numeric_limits<GIntBig>::max() / static_cast<int>(sizeof(ILIdx)))
     233             :     {
     234           0 :         CPLError(CE_Failure, CPLE_AppDefined, "IdxSize: integer overflow");
     235           0 :         return 0;
     236             :     }
     237         314 :     return sz * sizeof(ILIdx);
     238             : }
     239             : 
     240         876 : ILImage::ILImage()
     241             :     : dataoffset(0), idxoffset(0), quality(85), pageSizeBytes(0),
     242             :       size(ILSize(1, 1, 1, 1, 0)), pagesize(ILSize(384, 384, 1, 1, 0)),
     243         876 :       pagecount(pcount(size, pagesize)),
     244             : #ifdef HAVE_PNG
     245             :       comp(IL_PNG),
     246             : #else
     247             :       comp(IL_NONE),
     248             : #endif
     249             :       order(IL_Interleaved), nbo(false), hasNoData(FALSE), NoDataValue(0.0),
     250        1752 :       dt(GDT_Unknown), ci(GCI_Undefined)
     251             : {
     252         876 : }
     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        1712 : CPLString getFname(const CPLString &in, const char *ext)
     263             : {
     264        1712 :     if (strlen(in) < strlen(ext))
     265           0 :         return CPLString(ext);
     266             : 
     267        3424 :     CPLString ret(in);
     268             :     // Is it a web file with parameters?
     269        1712 :     size_t extlen = strlen(ext);
     270        1712 :     size_t qmark = ret.find_first_of('?');
     271        1712 :     if (!(qmark != std::string::npos && 0 == in.find("/vsicurl/http") &&
     272             :           qmark >= extlen))
     273        1712 :         qmark = ret.size();
     274        1712 :     return ret.replace(qmark - extlen, extlen, ext);
     275             : }
     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         732 : CPLString getFname(CPLXMLNode *node, const char *token, const CPLString &in,
     288             :                    const char *def)
     289             : {
     290        1464 :     CPLString fn = CPLGetXMLValue(node, token, "");
     291         732 :     if (fn.empty())  // Not provided
     292         720 :         return getFname(in, def);
     293          12 :     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          12 :     if (slashPos == 0                       // Starts with slash
     297           6 :         || (slashPos == 2 && fn[1] == ':')  // Starts with disk letter column
     298             :         // Does not start with dots then slash
     299           6 :         || (slashPos != fn.npos && slashPos != fn.find_first_not_of('.')) ||
     300           6 :         EQUALN(in, "<MRF_META>", 10)  // XML string input
     301          18 :         || in.find_first_of("\\/") ==
     302             :                in.npos)  // We can't get a basename from 'in'
     303           6 :         return fn;
     304             : 
     305             :     // Relative path, prepend the path from the in file name
     306          12 :     return in.substr(0, in.find_last_of("\\/") + 1) + fn;
     307             : }
     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        4607 : double getXMLNum(CPLXMLNode *node, const char *pszPath, double def)
     316             : {
     317        4607 :     const char *textval = CPLGetXMLValue(node, pszPath, nullptr);
     318        4607 :     if (textval)
     319        2996 :         return atof(textval);
     320        1611 :     return def;
     321             : }
     322             : 
     323             : //
     324             : // Calculate offset of index, pos is in pages
     325             : //
     326             : 
     327        9000 : GIntBig IdxOffset(const ILSize &pos, const ILImage &img)
     328             : {
     329        9000 :     return img.idxoffset +
     330        9000 :            sizeof(ILIdx) *
     331        9000 :                (pos.c +
     332        9000 :                 img.pagecount.c *
     333        9000 :                     (pos.x + img.pagecount.x *
     334        9000 :                                  (pos.y + img.pagecount.y *
     335        9000 :                                               static_cast<GIntBig>(pos.z))));
     336             : }
     337             : 
     338             : // Is compression type endianness dependent?
     339        8016 : bool is_Endianness_Dependent(GDALDataType dt, ILCompression comp)
     340             : {
     341             :     // Add here all endianness dependent compressions
     342        8016 :     if (IL_ZLIB == comp || IL_NONE == comp)
     343         672 :         if (GDALGetDataTypeSizeBytes(dt) > 1)
     344         454 :             return true;
     345        7562 :     return false;
     346             : }
     347             : 
     348         556 : MRFRasterBand *newMRFRasterBand(MRFDataset *pDS, const ILImage &image, int b,
     349             :                                 int level)
     350             : {
     351         556 :     MRFRasterBand *bnd = nullptr;
     352         556 :     CPLErrorReset();
     353         556 :     switch (pDS->current.comp)
     354             :     {
     355             : #ifdef HAVE_PNG
     356         159 :         case IL_PPNG:  // Uses the PNG code, just has a palette in each PNG
     357             :         case IL_PNG:
     358         159 :             bnd = new PNG_Band(pDS, image, b, level);
     359         159 :             break;
     360             : #endif
     361             : #ifdef HAVE_JPEG
     362          49 :         case IL_JPEG:
     363          49 :             bnd = new JPEG_Band(pDS, image, b, level);
     364          49 :             break;
     365             : #endif
     366             : #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             : #endif
     371         137 :         case IL_NONE:
     372         137 :             bnd = new Raw_Band(pDS, image, b, level);
     373         137 :             break;
     374             : #if defined(LERC)
     375          75 :         case IL_LERC:
     376          75 :             bnd = new LERC_Band(pDS, image, b, level);
     377          75 :             break;
     378             : #endif
     379             : #if defined(QB3_SUPPORT)
     380          53 :         case IL_QB3:
     381          53 :             bnd = new QB3_Band(pDS, image, b, level);
     382          53 :             break;
     383             : #endif
     384             :         // ZLIB is just raw + deflate
     385          26 :         case IL_ZLIB:
     386          26 :             bnd = new Raw_Band(pDS, image, b, level);
     387          26 :             bnd->SetDeflate(1);
     388          26 :             break;
     389             :             // Same for ZSTD
     390             : #if defined(ZSTD_SUPPORT)
     391          42 :         case IL_ZSTD:
     392          42 :             bnd = new Raw_Band(pDS, image, b, level);
     393          42 :             bnd->SetZstd(1);
     394          42 :             break;
     395             : #endif
     396          15 :         case IL_TIF:
     397          15 :             if (image.pageSizeBytes > INT_MAX - 1024)
     398           0 :                 return nullptr;
     399          15 :             bnd = new TIF_Band(pDS, image, b, level);
     400          15 :             break;
     401           0 :         default:
     402           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     403             :                      "Unsupported MRF compression");
     404           0 :             return nullptr;
     405             :     }
     406             : 
     407             :     // If something was flagged during band creation
     408         556 :     if (CPLGetLastErrorNo() != CE_None)
     409             :     {
     410          52 :         delete bnd;
     411          52 :         return nullptr;
     412             :     }
     413             : 
     414             :     // Copy the RW mode from the dataset
     415         504 :     bnd->SetAccess(pDS->eAccess);
     416         504 :     return bnd;
     417             : }
     418             : 
     419             : /**
     420             :  *\brief log in a given base
     421             :  */
     422          99 : double logbase(double val, double base)
     423             : {
     424          99 :     return log(val) / log(base);
     425             : }
     426             : 
     427             : /**
     428             :  *\brief Is logbase(val, base) an integer?
     429             :  *
     430             :  */
     431          33 : int IsPower(double value, double base)
     432             : {
     433          33 :     double v = logbase(value, base);
     434          33 :     return CPLIsEqual(v, int(v + 0.5));
     435             : }
     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         256 : CPLXMLNode *SearchXMLSiblings(CPLXMLNode *psRoot, const char *pszElement)
     457             : {
     458         256 :     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         256 :     if (pszElement[0] == '=')
     464           0 :         pszElement++;
     465             :     else
     466         256 :         psRoot = psRoot->psNext;
     467             : 
     468         256 :     for (; psRoot != nullptr; psRoot = psRoot->psNext)
     469         255 :         if ((psRoot->eType == CXT_Element || psRoot->eType == CXT_Attribute) &&
     470         255 :             EQUAL(pszElement, psRoot->pszValue))
     471         255 :             return psRoot;
     472           1 :     return nullptr;
     473             : }
     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        3528 : CPLString PrintDouble(double d, const char *frmt)
     480             : {
     481        7056 :     CPLString res;
     482        3528 :     res.FormatC(d, nullptr);
     483        3528 :     if (CPLStrtod(res.c_str(), nullptr) == d)
     484        3510 :         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          36 :     return CPLString().FormatC(d, frmt);
     491             : }
     492             : 
     493        3360 : void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
     494             :                         const char *pszVal)
     495             : {
     496        3360 :     CPLCreateXMLNode(parent, CXT_Attribute, pszName);
     497        3360 :     CPLSetXMLValue(parent, pszName, pszVal);
     498        3360 : }
     499             : 
     500        3356 : void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
     501             :                         const double val, const char *frmt)
     502             : {
     503        3356 :     XMLSetAttributeVal(parent, pszName, PrintDouble(val, frmt));
     504        3356 : }
     505             : 
     506         680 : CPLXMLNode *XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
     507             :                                const ILSize &sz, const char *frmt)
     508             : {
     509         680 :     CPLXMLNode *node = CPLCreateXMLNode(parent, CXT_Element, pszName);
     510         680 :     XMLSetAttributeVal(node, "x", sz.x, frmt);
     511         680 :     XMLSetAttributeVal(node, "y", sz.y, frmt);
     512         680 :     if (sz.z != 1)
     513           0 :         XMLSetAttributeVal(node, "z", sz.z, frmt);
     514         680 :     XMLSetAttributeVal(node, "c", sz.c, frmt);
     515         680 :     return node;
     516             : }
     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         129 : void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
     523             :                         std::vector<double> const &values)
     524             : {
     525         129 :     if (values.empty())
     526          59 :         return;
     527             : 
     528         140 :     CPLString value;
     529          70 :     double val = values[0];
     530          70 :     int single_val = true;
     531         140 :     for (int i = 0; i < int(values.size()); i++)
     532             :     {
     533          70 :         if (val != values[i])
     534           0 :             single_val = false;
     535          70 :         value.append(PrintDouble(values[i]) + " ");
     536             :     }
     537          70 :     value.pop_back();  // Cut the last space
     538          70 :     if (single_val)
     539          70 :         value = PrintDouble(values[0]);
     540          70 :     CPLCreateXMLNode(parent, CXT_Attribute, pszName);
     541          70 :     CPLSetXMLValue(parent, pszName, value);
     542             : }
     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         188 : int CheckFileSize(const char *fname, GIntBig sz, GDALAccess eAccess)
     551             : {
     552             : 
     553             :     VSIStatBufL statb;
     554         188 :     if (VSIStatL(fname, &statb))
     555           0 :         return false;
     556         188 :     if (statb.st_size >= sz)
     557          84 :         return true;
     558             : 
     559             :     // Don't change anything unless updating
     560         104 :     if (eAccess != GA_Update)
     561           0 :         return false;
     562             : 
     563             :     // There is no ftruncate in VSI, only truncate()
     564         104 :     VSILFILE *ifp = VSIFOpenL(fname, "r+b");
     565         104 :     if (ifp == nullptr)
     566           0 :         return false;
     567             : 
     568         104 :     int ret = VSIFTruncateL(ifp, sz);
     569         104 :     VSIFCloseL(ifp);
     570         104 :     return !ret;
     571             : }
     572             : 
     573             : NAMESPACE_MRF_END
     574             : 
     575             : /************************************************************************/
     576             : /*                          GDALRegister_MRF()                          */
     577             : /************************************************************************/
     578             : 
     579             : USING_NAMESPACE_MRF
     580             : 
     581        2038 : void GDALRegister_MRF()
     582             : {
     583        2038 :     if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
     584         283 :         return;
     585             : 
     586        1755 :     GDALDriver *driver = new GDALDriver();
     587        1755 :     MRFDriverSetCommonMetadata(driver);
     588             : 
     589        1755 :     driver->SetMetadataItem(
     590             :         GDAL_DMD_CREATIONOPTIONLIST,
     591             :         "<CreationOptionList>"
     592             :         "   <Option name='COMPRESS' type='string-select' "
     593             : #ifdef HAVE_PNG
     594             :         "default='PNG' description='PPNG = Palette PNG; DEFLATE = zlib '>"
     595             : #else
     596             :         "default='NONE' description='DEFLATE = zlib '>"
     597             : #endif
     598             : #ifdef HAVE_JPEG
     599             :         "       <Value>JPEG</Value>"
     600             : #endif
     601             : #ifdef HAVE_PNG
     602             :         "       <Value>PNG</Value>"
     603             :         "       <Value>PPNG</Value>"
     604             : #endif
     605             : #if defined(HAVE_JPEG) && defined(HAVE_PNG)
     606             :         "       <Value>JPNG</Value>"
     607             : #endif
     608             :         "       <Value>TIF</Value>"
     609             :         "       <Value>DEFLATE</Value>"
     610             :         "       <Value>NONE</Value>"
     611             : #if defined(LERC)
     612             :         "       <Value>LERC</Value>"
     613             : #endif
     614             : #if defined(ZSTD_SUPPORT)
     615             :         "       <Value>ZSTD</Value>"
     616             : #endif
     617             : #if defined(QB3_SUPPORT)
     618             :         "       <Value>QB3</Value>"
     619             : #endif
     620             :         "   </Option>"
     621             :         "   <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
     622             :         "       <Value>PIXEL</Value>"
     623             :         "       <Value>BAND</Value>"
     624             :         "   </Option>\n"
     625             :         "   <Option name='ZSIZE' type='int' description='Third dimension size' "
     626             :         "default='1'/>"
     627             :         "   <Option name='QUALITY' type='int' description='Compression "
     628             :         "dependent control value, for JPEG best=99, bad=0, default=85'/>\n"
     629             :         "   <Option name='BLOCKSIZE' type='int' description='Block size, both "
     630             :         "x and y, default 512'/>\n"
     631             :         "   <Option name='BLOCKXSIZE' type='int' description='Block x size, "
     632             :         "default=512'/>\n"
     633             :         "   <Option name='BLOCKYSIZE' type='int' description='Block y size, "
     634             :         "default=512'/>\n"
     635             :         "   <Option name='NETBYTEORDER' type='boolean' "
     636             :         "description='Force endian for certain compress options, default is "
     637             :         "host order'/>\n"
     638             :         "   <Option name='CACHEDSOURCE' type='string' "
     639             :         "description='The source raster, if this is a cache'/>\n"
     640             :         "   <Option name='UNIFORM_SCALE' type='int' description='Scale of "
     641             :         "overlays in MRF, usually 2'/>\n"
     642             :         "   <Option name='NOCOPY' type='boolean' description='Leave created "
     643             :         "MRF empty, default=no'/>\n"
     644             :         "   <Option name='DATANAME' type='string' description='Data file "
     645             :         "name'/>\n"
     646             :         "   <Option name='INDEXNAME' type='string' description='Index file "
     647             :         "name'/>\n"
     648             :         "   <Option name='SPACING' type='int' "
     649             :         "description='Leave this many unused bytes before each tile, "
     650             :         "default=0'/>\n"
     651             :         "   <Option name='PHOTOMETRIC' type='string-select' default='DEFAULT' "
     652             :         "description='Band interpretation, may affect block encoding'>\n"
     653             :         "       <Value>MULTISPECTRAL</Value>"
     654             :         "       <Value>RGB</Value>"
     655             :         "       <Value>YCC</Value>"
     656             :         "   </Option>\n"
     657             :         "   <Option name='OPTIONS' type='string' description='\n"
     658             :         "     Compression dependent parameters, space separated:\n"
     659             : #if defined(ZSTD_SUPPORT)
     660             :         "       ZSTD - boolean, enable libzstd as final stage, preferred over "
     661             :         "DEFLATE\n"
     662             : #endif
     663             :         "       DEFLATE - boolean, enable zlib as final stage\n"
     664             :         "       GZ - boolean, for DEFLATE enable gzip headers instead of zlib "
     665             :         "ones when using zlib\n"
     666             :         "       RAWZ - boolean, for DEFLATE disable all zlib headers\n"
     667             :         "       Z_STRATEGY - Z_HUFFMAN_ONLY | Z_FILTERED | Z_RLE | Z_FIXED: "
     668             :         "restricts DEFLATE and PNG strategy\n"
     669             : #if defined(LERC)
     670             :         "       LERC_PREC - numeric, set LERC precision, defaults to 0.5 for "
     671             :         "int and 0.001 for float\n"
     672             :         "       V1 - boolean, use LERC V1 (older) format\n"
     673             :         "       L2_VER - numeric, encode specific version of Lerc, default is "
     674             :         "library default\n"
     675             :         "                except for single band or INTERLEAVE=BAND, when it "
     676             :         "defaults to 2\n"
     677             : #endif
     678             :         "       OPTIMIZE - boolean, for JPEG, enables Huffman table "
     679             :         "optimization\n"
     680             : #if defined(BRUNSLI)
     681             :         "       JFIF - boolean, for JPEG, disable brunsli encoding\n"
     682             : #endif
     683             :         "'/>"
     684        1755 :         "</CreationOptionList>\n");
     685             : 
     686        1755 :     driver->pfnOpen = MRFDataset::Open;
     687        1755 :     driver->pfnCreateCopy = MRFDataset::CreateCopy;
     688        1755 :     driver->pfnCreate = MRFDataset::Create;
     689        1755 :     driver->pfnDelete = MRFDataset::Delete;
     690        1755 :     GetGDALDriverManager()->RegisterDriver(driver);
     691             : }

Generated by: LCOV version 1.14