LCOV - code coverage report
Current view: top level - frmts/ozi - ozidataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 24 291 8.2 %
Date: 2018-07-21 Functions: 3 19 15.8 %

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

Generated by: LCOV version 1.10