LCOV - code coverage report
Current view: directory - frmts/ozi - ozidataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 292 195 66.8 %
Date: 2012-12-26 Functions: 23 14 60.9 %

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

Generated by: LCOV version 1.7