LCOV - code coverage report
Current view: top level - frmts/ozi - ozidataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 20 296 6.8 %
Date: 2024-05-02 22:57:13 Functions: 2 19 10.5 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:   OZF2 and OZFx3 binary files driver
       4             :  * Purpose:  GDALDataset driver for OZF2 and OZFx3 binary files.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "gdal_frmts.h"
      30             : #include "gdal_pam.h"
      31             : #include "zlib.h"
      32             : 
      33             : /* g++ -fPIC -g -Wall frmts/ozi/ozidataset.cpp -shared -o gdal_OZI.so -Iport
      34             :  * -Igcore -Iogr -L. -lgdal  */
      35             : 
      36             : /************************************************************************/
      37             : /* ==================================================================== */
      38             : /*                              OZIDataset                              */
      39             : /* ==================================================================== */
      40             : /************************************************************************/
      41             : 
      42             : class OZIRasterBand;
      43             : 
      44             : class OZIDataset final : public GDALPamDataset
      45             : {
      46             :     friend class OZIRasterBand;
      47             : 
      48             :     VSILFILE *fp;
      49             :     int nZoomLevelCount;
      50             :     int *panZoomLevelOffsets;
      51             :     OZIRasterBand **papoOvrBands;
      52             :     vsi_l_offset nFileSize;
      53             : 
      54             :     int bOzi3;
      55             :     GByte nKeyInit;
      56             : 
      57             :   public:
      58             :     OZIDataset();
      59             :     virtual ~OZIDataset();
      60             : 
      61             :     static GDALDataset *Open(GDALOpenInfo *);
      62             :     static int Identify(GDALOpenInfo *);
      63             : };
      64             : 
      65             : /************************************************************************/
      66             : /* ==================================================================== */
      67             : /*                         OZIRasterBand                                */
      68             : /* ==================================================================== */
      69             : /************************************************************************/
      70             : 
      71             : class OZIRasterBand final : public GDALPamRasterBand
      72             : {
      73             :     friend class OZIDataset;
      74             : 
      75             :     int nXBlocks;
      76             :     int nZoomLevel;
      77             :     std::unique_ptr<GDALColorTable> poColorTable{};
      78             :     GByte *pabyTranslationTable;
      79             : 
      80             :   public:
      81             :     OZIRasterBand(OZIDataset *, int nZoomLevel, int nRasterXSize,
      82             :                   int nRasterYSize, int nXBlocks,
      83             :                   std::unique_ptr<GDALColorTable> &&poColorTableIn);
      84             :     virtual ~OZIRasterBand();
      85             : 
      86             :     virtual CPLErr IReadBlock(int, int, void *) override;
      87             :     virtual GDALColorInterp GetColorInterpretation() override;
      88             :     virtual GDALColorTable *GetColorTable() override;
      89             : 
      90             :     virtual int GetOverviewCount() override;
      91             :     virtual GDALRasterBand *GetOverview(int nLevel) override;
      92             : };
      93             : 
      94             : /************************************************************************/
      95             : /*                             I/O functions                            */
      96             : /************************************************************************/
      97             : 
      98             : constexpr GByte abyKey[] = {0x2D, 0x4A, 0x43, 0xF1, 0x27, 0x9B, 0x69,
      99             :                             0x4F, 0x36, 0x52, 0x87, 0xEC, 0x5F, 0x42,
     100             :                             0x53, 0x22, 0x9E, 0x8B, 0x2D, 0x83, 0x3D,
     101             :                             0xD2, 0x84, 0xBA, 0xD8, 0x5B};
     102             : 
     103           0 : static void OZIDecrypt(void *pabyVal, int n, GByte nKeyInit)
     104             : {
     105           0 :     for (int i = 0; i < n; i++)
     106             :     {
     107           0 :         reinterpret_cast<GByte *>(pabyVal)[i] ^=
     108           0 :             abyKey[i % sizeof(abyKey)] + nKeyInit;
     109             :     }
     110           0 : }
     111             : 
     112           0 : static int ReadInt(GByte **pptr)
     113             : {
     114             :     int nVal;
     115           0 :     memcpy(&nVal, *pptr, 4);
     116           0 :     *pptr += 4;
     117           0 :     CPL_LSBPTR32(&nVal);
     118           0 :     return nVal;
     119             : }
     120             : 
     121           0 : static short ReadShort(GByte **pptr)
     122             : {
     123             :     short nVal;
     124           0 :     memcpy(&nVal, *pptr, 2);
     125           0 :     *pptr += 2;
     126           0 :     CPL_LSBPTR16(&nVal);
     127           0 :     return nVal;
     128             : }
     129             : 
     130           0 : static int ReadInt(VSILFILE *fp, int bOzi3 = FALSE, int nKeyInit = 0)
     131             : {
     132             :     int nVal;
     133           0 :     VSIFReadL(&nVal, 1, 4, fp);
     134           0 :     if (bOzi3)
     135             :     {
     136             :         GByte abyVal[4];
     137           0 :         memcpy(&abyVal[0], &nVal, 4);
     138           0 :         OZIDecrypt(&abyVal[0], 4, static_cast<GByte>(nKeyInit));
     139           0 :         memcpy(&nVal, &abyVal[0], 4);
     140             :     }
     141           0 :     CPL_LSBPTR32(&nVal);
     142           0 :     return nVal;
     143             : }
     144             : 
     145           0 : static short ReadShort(VSILFILE *fp, int bOzi3 = FALSE, int nKeyInit = 0)
     146             : {
     147             :     short nVal;
     148           0 :     VSIFReadL(&nVal, 1, 2, fp);
     149           0 :     if (bOzi3)
     150             :     {
     151             :         GByte abyVal[2];
     152           0 :         memcpy(&abyVal[0], &nVal, 2);
     153           0 :         OZIDecrypt(&abyVal[0], 2, static_cast<GByte>(nKeyInit));
     154           0 :         memcpy(&nVal, &abyVal[0], 2);
     155             :     }
     156           0 :     CPL_LSBPTR16(&nVal);
     157           0 :     return nVal;
     158             : }
     159             : 
     160             : /************************************************************************/
     161             : /*                         OZIRasterBand()                             */
     162             : /************************************************************************/
     163             : 
     164           0 : OZIRasterBand::OZIRasterBand(OZIDataset *poDSIn, int nZoomLevelIn,
     165             :                              int nRasterXSizeIn, int nRasterYSizeIn,
     166             :                              int nXBlocksIn,
     167           0 :                              std::unique_ptr<GDALColorTable> &&poColorTableIn)
     168             :     : nXBlocks(nXBlocksIn), nZoomLevel(nZoomLevelIn),
     169           0 :       poColorTable(std::move(poColorTableIn)), pabyTranslationTable(nullptr)
     170             : {
     171           0 :     poDS = poDSIn;
     172           0 :     nBand = 1;
     173             : 
     174           0 :     eDataType = GDT_Byte;
     175             : 
     176           0 :     nBlockXSize = 64;
     177           0 :     nBlockYSize = 64;
     178             : 
     179           0 :     nRasterXSize = nRasterXSizeIn;
     180           0 :     nRasterYSize = nRasterYSizeIn;
     181           0 : }
     182             : 
     183             : /************************************************************************/
     184             : /*                        ~OZIRasterBand()                             */
     185             : /************************************************************************/
     186             : 
     187           0 : OZIRasterBand::~OZIRasterBand()
     188             : {
     189           0 :     CPLFree(pabyTranslationTable);
     190           0 : }
     191             : 
     192             : /************************************************************************/
     193             : /*                        GetColorInterpretation()                      */
     194             : /************************************************************************/
     195             : 
     196           0 : GDALColorInterp OZIRasterBand::GetColorInterpretation()
     197             : {
     198           0 :     return GCI_PaletteIndex;
     199             : }
     200             : 
     201             : /************************************************************************/
     202             : /*                            GetColorTable()                           */
     203             : /************************************************************************/
     204             : 
     205           0 : GDALColorTable *OZIRasterBand::GetColorTable()
     206             : {
     207           0 :     return poColorTable.get();
     208             : }
     209             : 
     210             : /************************************************************************/
     211             : /*                             IReadBlock()                             */
     212             : /************************************************************************/
     213             : 
     214           0 : CPLErr OZIRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     215             : 
     216             : {
     217           0 :     OZIDataset *poGDS = reinterpret_cast<OZIDataset *>(poDS);
     218             : 
     219           0 :     const int nBlock = nBlockYOff * nXBlocks + nBlockXOff;
     220             : 
     221           0 :     VSIFSeekL(poGDS->fp,
     222           0 :               poGDS->panZoomLevelOffsets[nZoomLevel] + 12 + 1024 + 4 * nBlock,
     223             :               SEEK_SET);
     224           0 :     const int nPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
     225           0 :     if (nPointer < 0 || (vsi_l_offset)nPointer >= poGDS->nFileSize)
     226             :     {
     227           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     228             :                  "Invalid offset for block (%d, %d) : %d", nBlockXOff,
     229             :                  nBlockYOff, nPointer);
     230           0 :         return CE_Failure;
     231             :     }
     232           0 :     int nNextPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
     233           0 :     if (nNextPointer <= nPointer + 16 ||
     234           0 :         (vsi_l_offset)nNextPointer >= poGDS->nFileSize ||
     235           0 :         nNextPointer - nPointer > 10 * 64 * 64)
     236             :     {
     237           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     238             :                  "Invalid next offset for block (%d, %d) : %d", nBlockXOff,
     239             :                  nBlockYOff, nNextPointer);
     240           0 :         return CE_Failure;
     241             :     }
     242             : 
     243           0 :     VSIFSeekL(poGDS->fp, nPointer, SEEK_SET);
     244             : 
     245           0 :     const int nToRead = nNextPointer - nPointer;
     246           0 :     GByte *pabyZlibBuffer = reinterpret_cast<GByte *>(CPLMalloc(nToRead));
     247           0 :     if (VSIFReadL(pabyZlibBuffer, nToRead, 1, poGDS->fp) != 1)
     248             :     {
     249           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     250             :                  "Not enough byte read for block (%d, %d)", nBlockXOff,
     251             :                  nBlockYOff);
     252           0 :         CPLFree(pabyZlibBuffer);
     253           0 :         return CE_Failure;
     254             :     }
     255             : 
     256           0 :     if (poGDS->bOzi3)
     257           0 :         OZIDecrypt(pabyZlibBuffer, 16, poGDS->nKeyInit);
     258             : 
     259           0 :     if (pabyZlibBuffer[0] != 0x78 || pabyZlibBuffer[1] != 0xDA)
     260             :     {
     261           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     262             :                  "Bad ZLIB signature for block (%d, %d) : 0x%02X 0x%02X",
     263           0 :                  nBlockXOff, nBlockYOff, pabyZlibBuffer[0], pabyZlibBuffer[1]);
     264           0 :         CPLFree(pabyZlibBuffer);
     265           0 :         return CE_Failure;
     266             :     }
     267             : 
     268             :     z_stream stream;
     269           0 :     memset(&stream, 0, sizeof(stream));
     270           0 :     stream.zalloc = (alloc_func) nullptr;
     271           0 :     stream.zfree = (free_func) nullptr;
     272           0 :     stream.opaque = (voidpf) nullptr;
     273           0 :     stream.next_in = pabyZlibBuffer + 2;
     274           0 :     stream.avail_in = nToRead - 2;
     275             : 
     276           0 :     int err = inflateInit2(&(stream), -MAX_WBITS);
     277             : 
     278           0 :     for (int i = 0; i < 64 && err == Z_OK; i++)
     279             :     {
     280           0 :         stream.next_out = reinterpret_cast<Bytef *>(pImage) + (63 - i) * 64;
     281           0 :         stream.avail_out = 64;
     282           0 :         err = inflate(&(stream), Z_NO_FLUSH);
     283           0 :         if (err != Z_OK && err != Z_STREAM_END)
     284           0 :             break;
     285             : 
     286           0 :         if (pabyTranslationTable)
     287             :         {
     288           0 :             GByte *ptr = reinterpret_cast<GByte *>(pImage) + (63 - i) * 64;
     289           0 :             for (int j = 0; j < 64; j++)
     290             :             {
     291           0 :                 *ptr = pabyTranslationTable[*ptr];
     292           0 :                 ptr++;
     293             :             }
     294             :         }
     295             :     }
     296             : 
     297           0 :     inflateEnd(&stream);
     298             : 
     299           0 :     CPLFree(pabyZlibBuffer);
     300             : 
     301           0 :     return (err == Z_OK || err == Z_STREAM_END) ? CE_None : CE_Failure;
     302             : }
     303             : 
     304             : /************************************************************************/
     305             : /*                         GetOverviewCount()                            */
     306             : /************************************************************************/
     307             : 
     308           0 : int OZIRasterBand::GetOverviewCount()
     309             : {
     310           0 :     if (nZoomLevel != 0)
     311           0 :         return 0;
     312             : 
     313           0 :     OZIDataset *poGDS = reinterpret_cast<OZIDataset *>(poDS);
     314           0 :     return poGDS->nZoomLevelCount - 1;
     315             : }
     316             : 
     317             : /************************************************************************/
     318             : /*                            GetOverview()                             */
     319             : /************************************************************************/
     320             : 
     321           0 : GDALRasterBand *OZIRasterBand::GetOverview(int nLevel)
     322             : {
     323           0 :     if (nZoomLevel != 0)
     324           0 :         return nullptr;
     325             : 
     326           0 :     OZIDataset *poGDS = reinterpret_cast<OZIDataset *>(poDS);
     327           0 :     if (nLevel < 0 || nLevel >= poGDS->nZoomLevelCount - 1)
     328           0 :         return nullptr;
     329             : 
     330           0 :     return poGDS->papoOvrBands[nLevel + 1];
     331             : }
     332             : 
     333             : /************************************************************************/
     334             : /*                            ~OZIDataset()                            */
     335             : /************************************************************************/
     336             : 
     337           0 : OZIDataset::OZIDataset()
     338             :     : fp(nullptr), nZoomLevelCount(0), panZoomLevelOffsets(nullptr),
     339           0 :       papoOvrBands(nullptr), nFileSize(0), bOzi3(FALSE), nKeyInit(0)
     340             : {
     341           0 : }
     342             : 
     343             : /************************************************************************/
     344             : /*                            ~OZIDataset()                            */
     345             : /************************************************************************/
     346             : 
     347           0 : OZIDataset::~OZIDataset()
     348             : {
     349           0 :     if (fp)
     350           0 :         VSIFCloseL(fp);
     351           0 :     if (papoOvrBands != nullptr)
     352             :     {
     353             :         /* start at 1: do not destroy the base band ! */
     354           0 :         for (int i = 1; i < nZoomLevelCount; i++)
     355           0 :             delete papoOvrBands[i];
     356           0 :         CPLFree(papoOvrBands);
     357             :     }
     358           0 :     CPLFree(panZoomLevelOffsets);
     359           0 : }
     360             : 
     361             : /************************************************************************/
     362             : /*                             Identify()                               */
     363             : /************************************************************************/
     364             : 
     365       47992 : int OZIDataset::Identify(GDALOpenInfo *poOpenInfo)
     366             : {
     367       47992 :     if (poOpenInfo->nHeaderBytes < 14)
     368       45326 :         return FALSE;
     369             : 
     370        2666 :     if (poOpenInfo->pabyHeader[0] == 0x80 && poOpenInfo->pabyHeader[1] == 0x77)
     371           0 :         return TRUE;
     372             : 
     373        2666 :     return poOpenInfo->pabyHeader[0] == 0x78 &&
     374           0 :            poOpenInfo->pabyHeader[1] == 0x77 &&
     375           0 :            poOpenInfo->pabyHeader[6] == 0x40 &&
     376           0 :            poOpenInfo->pabyHeader[7] == 0x00 &&
     377           0 :            poOpenInfo->pabyHeader[8] == 0x01 &&
     378           0 :            poOpenInfo->pabyHeader[9] == 0x00 &&
     379           0 :            poOpenInfo->pabyHeader[10] == 0x36 &&
     380           0 :            poOpenInfo->pabyHeader[11] == 0x04 &&
     381        2666 :            poOpenInfo->pabyHeader[12] == 0x00 &&
     382        2666 :            poOpenInfo->pabyHeader[13] == 0x00;
     383             : }
     384             : 
     385             : /************************************************************************/
     386             : /*                                Open()                                */
     387             : /************************************************************************/
     388             : 
     389           0 : GDALDataset *OZIDataset::Open(GDALOpenInfo *poOpenInfo)
     390             : 
     391             : {
     392           0 :     if (!Identify(poOpenInfo))
     393           0 :         return nullptr;
     394             : 
     395             :     GByte abyHeader[14];
     396           0 :     memcpy(abyHeader, poOpenInfo->pabyHeader, 14);
     397             : 
     398           0 :     int bOzi3 = (abyHeader[0] == 0x80 && abyHeader[1] == 0x77);
     399             : 
     400           0 :     const CPLString osImgFilename = poOpenInfo->pszFilename;
     401           0 :     VSILFILE *fp = VSIFOpenL(osImgFilename.c_str(), "rb");
     402           0 :     if (fp == nullptr)
     403           0 :         return nullptr;
     404             : 
     405           0 :     OZIDataset *poDS = new OZIDataset();
     406           0 :     poDS->fp = fp;
     407             : 
     408           0 :     GByte nKeyInit = 0;
     409           0 :     if (bOzi3)
     410             :     {
     411           0 :         VSIFSeekL(fp, 14, SEEK_SET);
     412             : 
     413           0 :         GByte nRandomNumber = 0;
     414           0 :         VSIFReadL(&nRandomNumber, 1, 1, fp);
     415             :         // printf("nRandomNumber = %d\n", nRandomNumber);
     416           0 :         if (nRandomNumber < 0x94)
     417             :         {
     418           0 :             delete poDS;
     419           0 :             return nullptr;
     420             :         }
     421           0 :         VSIFSeekL(fp, 0x93, SEEK_CUR);
     422           0 :         VSIFReadL(&nKeyInit, 1, 1, fp);
     423             : 
     424           0 :         VSIFSeekL(fp, 0, SEEK_SET);
     425           0 :         VSIFReadL(abyHeader, 1, 14, fp);
     426           0 :         OZIDecrypt(abyHeader, 14, nKeyInit);
     427           0 :         if (!(abyHeader[6] == 0x40 && abyHeader[7] == 0x00 &&
     428           0 :               abyHeader[8] == 0x01 && abyHeader[9] == 0x00 &&
     429           0 :               abyHeader[10] == 0x36 && abyHeader[11] == 0x04 &&
     430           0 :               abyHeader[12] == 0x00 && abyHeader[13] == 0x00))
     431             :         {
     432           0 :             delete poDS;
     433           0 :             return nullptr;
     434             :         }
     435             : 
     436           0 :         VSIFSeekL(fp, 14 + 1 + nRandomNumber, SEEK_SET);
     437           0 :         const int nMagic = ReadInt(fp, bOzi3, nKeyInit);
     438           0 :         CPLDebug("OZI", "OZI version code : 0x%08X", nMagic);
     439             : 
     440           0 :         poDS->bOzi3 = bOzi3;
     441             :     }
     442             :     else
     443             :     {
     444           0 :         VSIFSeekL(fp, 14, SEEK_SET);
     445             :     }
     446             : 
     447             :     GByte abyHeader2[40], abyHeader2_Backup[40];
     448           0 :     VSIFReadL(abyHeader2, 40, 1, fp);
     449           0 :     memcpy(abyHeader2_Backup, abyHeader2, 40);
     450             : 
     451             :     /* There's apparently a relationship between the nMagic number */
     452             :     /* and the nKeyInit, but I'm too lazy to add switch/cases that might */
     453             :     /* be not exhaustive, so let's try the 'brute force' attack !!! */
     454             :     /* It is much so funny to be able to run one in a few microseconds :-) */
     455           0 :     for (int i = 0; i < 256; i++)
     456             :     {
     457           0 :         nKeyInit = static_cast<GByte>(i);
     458           0 :         GByte *pabyHeader2 = abyHeader2;
     459           0 :         if (bOzi3)
     460           0 :             OZIDecrypt(abyHeader2, 40, nKeyInit);
     461             : 
     462           0 :         const int nHeaderSize = ReadInt(&pabyHeader2); /* should be 40 */
     463           0 :         poDS->nRasterXSize = ReadInt(&pabyHeader2);
     464           0 :         poDS->nRasterYSize = ReadInt(&pabyHeader2);
     465           0 :         const int nDepth = ReadShort(&pabyHeader2); /* should be 1 */
     466           0 :         const int nBPP = ReadShort(&pabyHeader2);   /* should be 8 */
     467           0 :         ReadInt(&pabyHeader2);                      /* reserved */
     468           0 :         ReadInt(&pabyHeader2); /* pixel number (height * width) : unused */
     469           0 :         ReadInt(&pabyHeader2); /* reserved */
     470           0 :         ReadInt(&pabyHeader2); /* reserved */
     471           0 :         ReadInt(&pabyHeader2); /* ?? 0x100 */
     472           0 :         ReadInt(&pabyHeader2); /* ?? 0x100 */
     473             : 
     474           0 :         if (nHeaderSize != 40 || nDepth != 1 || nBPP != 8)
     475             :         {
     476           0 :             if (bOzi3)
     477             :             {
     478           0 :                 if (nKeyInit != 255)
     479             :                 {
     480           0 :                     memcpy(abyHeader2, abyHeader2_Backup, 40);
     481           0 :                     continue;
     482             :                 }
     483             :                 else
     484             :                 {
     485           0 :                     CPLDebug("OZI", "Cannot decipher 2nd header. Sorry...");
     486           0 :                     delete poDS;
     487           0 :                     return nullptr;
     488             :                 }
     489             :             }
     490             :             else
     491             :             {
     492           0 :                 CPLDebug("OZI", "nHeaderSize = %d, nDepth = %d, nBPP = %d",
     493             :                          nHeaderSize, nDepth, nBPP);
     494           0 :                 delete poDS;
     495           0 :                 return nullptr;
     496             :             }
     497             :         }
     498             :         else
     499             :             break;
     500             :     }
     501           0 :     poDS->nKeyInit = nKeyInit;
     502             : 
     503           0 :     int nSeparator = ReadInt(fp);
     504           0 :     if (!bOzi3 && nSeparator != 0x77777777)
     505             :     {
     506           0 :         CPLDebug("OZI", "didn't get end of header2 marker");
     507           0 :         delete poDS;
     508           0 :         return nullptr;
     509             :     }
     510             : 
     511           0 :     poDS->nZoomLevelCount = ReadShort(fp);
     512             : 
     513             : #ifdef DEBUG_VERBOSE
     514             :     CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
     515             : #endif
     516             : 
     517           0 :     if (poDS->nZoomLevelCount < 0 || poDS->nZoomLevelCount >= 256)
     518             :     {
     519           0 :         CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
     520           0 :         delete poDS;
     521           0 :         return nullptr;
     522             :     }
     523             : 
     524             :     /* Skip array of zoom level percentage. We don't need it for GDAL */
     525           0 :     VSIFSeekL(fp, sizeof(float) * poDS->nZoomLevelCount, SEEK_CUR);
     526             : 
     527           0 :     nSeparator = ReadInt(fp);
     528           0 :     if (!bOzi3 && nSeparator != 0x77777777)
     529             :     {
     530             :         /* Some files have 8 extra bytes before the marker. I'm not sure */
     531             :         /* what they are used for. So just skip them and hope that */
     532             :         /* we'll find the marker */
     533           0 :         CPL_IGNORE_RET_VAL(ReadInt(fp));
     534           0 :         nSeparator = ReadInt(fp);
     535           0 :         if (nSeparator != 0x77777777)
     536             :         {
     537           0 :             CPLDebug("OZI", "didn't get end of zoom levels marker");
     538           0 :             delete poDS;
     539           0 :             return nullptr;
     540             :         }
     541             :     }
     542             : 
     543           0 :     VSIFSeekL(fp, 0, SEEK_END);
     544           0 :     const vsi_l_offset nFileSize = VSIFTellL(fp);
     545           0 :     poDS->nFileSize = nFileSize;
     546           0 :     VSIFSeekL(fp, nFileSize - 4, SEEK_SET);
     547           0 :     const int nZoomLevelTableOffset = ReadInt(fp, bOzi3, nKeyInit);
     548           0 :     if (nZoomLevelTableOffset < 0 ||
     549           0 :         (vsi_l_offset)nZoomLevelTableOffset >= nFileSize)
     550             :     {
     551           0 :         CPLDebug("OZI", "nZoomLevelTableOffset = %d", nZoomLevelTableOffset);
     552           0 :         delete poDS;
     553           0 :         return nullptr;
     554             :     }
     555             : 
     556           0 :     VSIFSeekL(fp, nZoomLevelTableOffset, SEEK_SET);
     557             : 
     558           0 :     poDS->panZoomLevelOffsets =
     559           0 :         reinterpret_cast<int *>(CPLMalloc(sizeof(int) * poDS->nZoomLevelCount));
     560             : 
     561           0 :     for (int i = 0; i < poDS->nZoomLevelCount; i++)
     562             :     {
     563           0 :         poDS->panZoomLevelOffsets[i] = ReadInt(fp, bOzi3, nKeyInit);
     564           0 :         if (poDS->panZoomLevelOffsets[i] < 0 ||
     565           0 :             (vsi_l_offset)poDS->panZoomLevelOffsets[i] >= nFileSize)
     566             :         {
     567           0 :             CPLDebug("OZI", "panZoomLevelOffsets[%d] = %d", i,
     568           0 :                      poDS->panZoomLevelOffsets[i]);
     569           0 :             delete poDS;
     570           0 :             return nullptr;
     571             :         }
     572             :     }
     573             : 
     574           0 :     poDS->papoOvrBands = reinterpret_cast<OZIRasterBand **>(
     575           0 :         CPLCalloc(sizeof(OZIRasterBand *), poDS->nZoomLevelCount));
     576             : 
     577           0 :     for (int i = 0; i < poDS->nZoomLevelCount; i++)
     578             :     {
     579           0 :         VSIFSeekL(fp, poDS->panZoomLevelOffsets[i], SEEK_SET);
     580           0 :         const int nW = ReadInt(fp, bOzi3, nKeyInit);
     581           0 :         const int nH = ReadInt(fp, bOzi3, nKeyInit);
     582           0 :         const short nTileX = ReadShort(fp, bOzi3, nKeyInit);
     583           0 :         const short nTileY = ReadShort(fp, bOzi3, nKeyInit);
     584           0 :         if (i == 0 && (nW != poDS->nRasterXSize || nH != poDS->nRasterYSize))
     585             :         {
     586           0 :             CPLDebug("OZI",
     587             :                      "zoom[%d] inconsistent dimensions for zoom level 0 "
     588             :                      ": nW=%d, nH=%d, nTileX=%d, nTileY=%d, nRasterXSize=%d, "
     589             :                      "nRasterYSize=%d",
     590             :                      i, nW, nH, nTileX, nTileY, poDS->nRasterXSize,
     591             :                      poDS->nRasterYSize);
     592           0 :             delete poDS;
     593           0 :             return nullptr;
     594             :         }
     595             :         /* Note (#3895): some files such as world.ozf2 provided with OziExplorer
     596             :          */
     597             :         /* expose nTileY=33, but have nH=2048, so only require 32 tiles in
     598             :          * vertical dimension. */
     599             :         /* So there's apparently one extra and useless tile that will be ignored
     600             :          */
     601             :         /* without causing apparent issues */
     602             :         /* Some other files have more tile in horizontal direction than needed,
     603             :          * so let's */
     604             :         /* accept that. But in that case we really need to keep the nTileX value
     605             :          * for IReadBlock() */
     606             :         /* to work properly */
     607           0 :         if ((nW + 63) / 64 > nTileX || (nH + 63) / 64 > nTileY)
     608             :         {
     609           0 :             CPLDebug("OZI",
     610             :                      "zoom[%d] unexpected number of tiles : nW=%d, "
     611             :                      "nH=%d, nTileX=%d, nTileY=%d",
     612             :                      i, nW, nH, nTileX, nTileY);
     613           0 :             delete poDS;
     614           0 :             return nullptr;
     615             :         }
     616             : 
     617           0 :         auto poColorTable = std::make_unique<GDALColorTable>();
     618             :         GByte abyColorTable[256 * 4];
     619           0 :         VSIFReadL(abyColorTable, 1, 1024, fp);
     620           0 :         if (bOzi3)
     621           0 :             OZIDecrypt(abyColorTable, 1024, nKeyInit);
     622           0 :         for (int j = 0; j < 256; j++)
     623             :         {
     624             :             GDALColorEntry sEntry;
     625           0 :             sEntry.c1 = abyColorTable[4 * j + 2];
     626           0 :             sEntry.c2 = abyColorTable[4 * j + 1];
     627           0 :             sEntry.c3 = abyColorTable[4 * j + 0];
     628           0 :             sEntry.c4 = 255;
     629           0 :             poColorTable->SetColorEntry(j, &sEntry);
     630             :         }
     631             : 
     632           0 :         poDS->papoOvrBands[i] =
     633           0 :             new OZIRasterBand(poDS, i, nW, nH, nTileX, std::move(poColorTable));
     634             : 
     635           0 :         if (i > 0)
     636             :         {
     637             :             GByte *pabyTranslationTable =
     638           0 :                 poDS->papoOvrBands[i]->GetIndexColorTranslationTo(
     639           0 :                     poDS->papoOvrBands[0], nullptr, nullptr);
     640             : 
     641           0 :             poDS->papoOvrBands[i]->poColorTable.reset(
     642           0 :                 poDS->papoOvrBands[0]->poColorTable->Clone());
     643           0 :             poDS->papoOvrBands[i]->pabyTranslationTable = pabyTranslationTable;
     644             :         }
     645             :     }
     646             : 
     647           0 :     poDS->SetBand(1, poDS->papoOvrBands[0]);
     648             : 
     649             :     /* -------------------------------------------------------------------- */
     650             :     /*      Initialize any PAM information.                                 */
     651             :     /* -------------------------------------------------------------------- */
     652           0 :     poDS->SetDescription(poOpenInfo->pszFilename);
     653           0 :     poDS->TryLoadXML();
     654             : 
     655             :     /* -------------------------------------------------------------------- */
     656             :     /*      Support overviews.                                              */
     657             :     /* -------------------------------------------------------------------- */
     658           0 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     659           0 :     return poDS;
     660             : }
     661             : 
     662             : /************************************************************************/
     663             : /*                         GDALRegister_OZI()                           */
     664             : /************************************************************************/
     665             : 
     666        1512 : void GDALRegister_OZI()
     667             : 
     668             : {
     669        1512 :     if (!GDAL_CHECK_VERSION("OZI driver"))
     670           0 :         return;
     671             : 
     672        1512 :     if (GDALGetDriverByName("OZI") != nullptr)
     673         295 :         return;
     674             : 
     675        1217 :     GDALDriver *poDriver = new GDALDriver();
     676             : 
     677        1217 :     poDriver->SetDescription("OZI");
     678        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     679        1217 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OziExplorer Image File");
     680        1217 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ozi.html");
     681        1217 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     682             : 
     683        1217 :     poDriver->pfnOpen = OZIDataset::Open;
     684        1217 :     poDriver->pfnIdentify = OZIDataset::Identify;
     685             : 
     686        1217 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     687             : }

Generated by: LCOV version 1.14