LCOV - code coverage report
Current view: directory - frmts/ozi - ozidataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 337 229 68.0 %
Date: 2012-04-28 Functions: 28 17 60.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ozidataset.cpp 21930 2011-03-11 13:27:22Z dron $
       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 21930 2011-03-11 13:27:22Z dron $");
      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** papoBands;
      57                 :     vsi_l_offset nFileSize;
      58                 : 
      59                 :     int bOzi3;
      60                 :     GByte nKeyInit;
      61                 : 
      62                 :     double    adfGeoTransform[6];
      63                 :     char*     pszWKT;
      64                 :     int       nGCPCount;
      65                 :     GDAL_GCP* pasGCPs;
      66                 :     int       bReadMapFileSuccess;
      67                 : 
      68                 :   public:
      69                 :                  OZIDataset();
      70                 :     virtual     ~OZIDataset();
      71                 : 
      72                 :     virtual const char* GetProjectionRef();
      73                 :     virtual CPLErr      GetGeoTransform( double * );
      74                 : 
      75                 :     virtual int    GetGCPCount();
      76                 :     virtual const char *GetGCPProjection();
      77                 :     virtual const GDAL_GCP *GetGCPs();
      78                 : 
      79                 :     static GDALDataset *Open( GDALOpenInfo * );
      80                 :     static int          Identify( GDALOpenInfo * );
      81                 : };
      82                 : 
      83                 : /************************************************************************/
      84                 : /* ==================================================================== */
      85                 : /*                         OZIRasterBand                                */
      86                 : /* ==================================================================== */
      87                 : /************************************************************************/
      88                 : 
      89                 : class OZIRasterBand : public GDALPamRasterBand
      90                 : {
      91                 :     friend class OZIDataset;
      92                 : 
      93                 :     int nXBlocks;
      94                 :     int nZoomLevel;
      95                 :     GDALColorTable* poColorTable;
      96                 :     GByte* pabyTranslationTable;
      97                 : 
      98                 :   public:
      99                 : 
     100                 :                 OZIRasterBand( OZIDataset *, int nZoomLevel,
     101                 :                                int nRasterXSize, int nRasterYSize,
     102                 :                                int nXBlocks,
     103                 :                                GDALColorTable* poColorTable);
     104                 :     virtual    ~OZIRasterBand();
     105                 : 
     106                 :     virtual CPLErr IReadBlock( int, int, void * );
     107                 :     virtual GDALColorInterp GetColorInterpretation();
     108                 :     virtual GDALColorTable *GetColorTable();
     109                 : 
     110                 :     virtual int         GetOverviewCount();
     111                 :     virtual GDALRasterBand* GetOverview(int nLevel);
     112                 : };
     113                 : 
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                             I/O functions                            */
     117                 : /************************************************************************/
     118                 : 
     119                 : static const GByte abyKey[] =
     120                 : {
     121                 :     0x2D, 0x4A, 0x43, 0xF1, 0x27, 0x9B, 0x69, 0x4F,
     122                 :     0x36, 0x52, 0x87, 0xEC, 0x5F, 0x42, 0x53, 0x22,
     123                 :     0x9E, 0x8B, 0x2D, 0x83, 0x3D, 0xD2, 0x84, 0xBA,
     124                 :     0xD8, 0x5B
     125                 : };
     126                 : 
     127               0 : static void OZIDecrypt(void *pabyVal, int n, GByte nKeyInit)
     128                 : {
     129                 :     int i;
     130               0 :     for(i = 0; i < n; i++)
     131                 :     {
     132               0 :         ((GByte*)pabyVal)[i] ^= abyKey[i % sizeof(abyKey)] + nKeyInit;
     133                 :     }
     134               0 : }
     135                 : 
     136              18 : static int ReadInt(GByte**pptr)
     137                 : {
     138                 :     int nVal;
     139              18 :     memcpy(&nVal, *pptr, 4);
     140              18 :     *pptr += 4;
     141                 :     CPL_LSBPTR32(&nVal);
     142              18 :     return nVal;
     143                 : }
     144                 : 
     145               4 : static short ReadShort(GByte**pptr)
     146                 : {
     147                 :     short nVal;
     148               4 :     memcpy(&nVal, *pptr, 2);
     149               4 :     *pptr += 2;
     150                 :     CPL_LSBPTR16(&nVal);
     151               4 :     return nVal;
     152                 : }
     153                 : 
     154            1788 : static int ReadInt(VSILFILE* fp, int bOzi3 = FALSE, int nKeyInit = 0)
     155                 : {
     156                 :     int nVal;
     157            1788 :     VSIFReadL(&nVal, 1, 4, fp);
     158            1788 :     if (bOzi3) OZIDecrypt(&nVal, 4, (GByte) nKeyInit);
     159                 :     CPL_LSBPTR32(&nVal);
     160            1788 :     return nVal;
     161                 : }
     162                 : 
     163              38 : static short ReadShort(VSILFILE* fp, int bOzi3 = FALSE, int nKeyInit = 0)
     164                 : {
     165                 :     short nVal;
     166              38 :     VSIFReadL(&nVal, 1, 2, fp);
     167              38 :     if (bOzi3) OZIDecrypt(&nVal, 2, (GByte) nKeyInit);
     168                 :     CPL_LSBPTR16(&nVal);
     169              38 :     return nVal;
     170                 : }
     171                 : 
     172                 : /************************************************************************/
     173                 : /*                         OZIRasterBand()                             */
     174                 : /************************************************************************/
     175                 : 
     176              18 : OZIRasterBand::OZIRasterBand( OZIDataset *poDS, int nZoomLevel,
     177                 :                               int nRasterXSize, int nRasterYSize,
     178                 :                               int nXBlocks,
     179              18 :                               GDALColorTable* poColorTable )
     180                 : 
     181                 : {
     182              18 :     this->poDS = poDS;
     183              18 :     this->nBand = 1;
     184                 : 
     185              18 :     eDataType = GDT_Byte;
     186                 : 
     187              18 :     nBlockXSize = 64;
     188              18 :     nBlockYSize = 64;
     189                 : 
     190              18 :     this->nZoomLevel = nZoomLevel;
     191              18 :     this->nRasterXSize = nRasterXSize;
     192              18 :     this->nRasterYSize = nRasterYSize;
     193              18 :     this->poColorTable = poColorTable;
     194              18 :     this->nXBlocks = nXBlocks;
     195                 : 
     196              18 :     pabyTranslationTable = NULL;
     197              18 : }
     198                 : 
     199                 : /************************************************************************/
     200                 : /*                        ~OZIRasterBand()                             */
     201                 : /************************************************************************/
     202                 : 
     203              18 : OZIRasterBand::~OZIRasterBand()
     204                 : {
     205              18 :     delete poColorTable;
     206              18 :     CPLFree(pabyTranslationTable);
     207              18 : }
     208                 : 
     209                 : 
     210                 : /************************************************************************/
     211                 : /*                        GetColorInterpretation()                      */
     212                 : /************************************************************************/
     213                 : 
     214              32 : GDALColorInterp OZIRasterBand::GetColorInterpretation()
     215                 : {
     216              32 :     return GCI_PaletteIndex;
     217                 : }
     218                 : 
     219                 : /************************************************************************/
     220                 : /*                            GetColorTable()                           */
     221                 : /************************************************************************/
     222                 : 
     223              32 : GDALColorTable* OZIRasterBand::GetColorTable()
     224                 : {
     225              32 :     return poColorTable;
     226                 : }
     227                 : 
     228                 : /************************************************************************/
     229                 : /*                             IReadBlock()                             */
     230                 : /************************************************************************/
     231                 : 
     232             864 : CPLErr OZIRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     233                 :                                   void * pImage )
     234                 : 
     235                 : {
     236             864 :     OZIDataset *poGDS = (OZIDataset *) poDS;
     237                 : 
     238             864 :     int nBlock = nBlockYOff * nXBlocks + nBlockXOff;
     239                 : 
     240             864 :     VSIFSeekL(poGDS->fp, poGDS->panZoomLevelOffsets[nZoomLevel] +
     241             864 :                          12 + 1024 + 4 * nBlock, SEEK_SET);
     242             864 :     int nPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
     243             864 :     if (nPointer < 0  || (vsi_l_offset)nPointer >= poGDS->nFileSize)
     244                 :     {
     245                 :         CPLError(CE_Failure, CPLE_AppDefined,
     246                 :                  "Invalid offset for block (%d, %d) : %d",
     247               0 :                  nBlockXOff, nBlockYOff, nPointer);
     248               0 :         return CE_Failure;
     249                 :     }
     250             864 :     int nNextPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
     251             864 :     if (nNextPointer <= nPointer + 16  ||
     252                 :         (vsi_l_offset)nNextPointer >= poGDS->nFileSize)
     253                 :     {
     254                 :         CPLError(CE_Failure, CPLE_AppDefined,
     255                 :                  "Invalid next offset for block (%d, %d) : %d",
     256               0 :                  nBlockXOff, nBlockYOff, nNextPointer);
     257               0 :         return CE_Failure;
     258                 :     }
     259                 : 
     260             864 :     VSIFSeekL(poGDS->fp, nPointer, SEEK_SET);
     261                 : 
     262             864 :     int nToRead = nNextPointer - nPointer;
     263             864 :     GByte* pabyZlibBuffer = (GByte*)CPLMalloc(nToRead);
     264             864 :     if (VSIFReadL(pabyZlibBuffer, nToRead, 1, poGDS->fp) != 1)
     265                 :     {
     266                 :         CPLError(CE_Failure, CPLE_AppDefined,
     267                 :                  "Not enough byte read for block (%d, %d)",
     268               0 :                  nBlockXOff, nBlockYOff);
     269               0 :         CPLFree(pabyZlibBuffer);
     270               0 :         return CE_Failure;
     271                 :     }
     272                 : 
     273             864 :     if (poGDS->bOzi3)
     274               0 :         OZIDecrypt(pabyZlibBuffer, 16, poGDS->nKeyInit);
     275                 : 
     276            1728 :     if (pabyZlibBuffer[0] != 0x78 ||
     277             864 :         pabyZlibBuffer[1] != 0xDA)
     278                 :     {
     279                 :         CPLError(CE_Failure, CPLE_AppDefined,
     280                 :                  "Bad ZLIB signature for block (%d, %d) : 0x%02X 0x%02X",
     281               0 :                  nBlockXOff, nBlockYOff, pabyZlibBuffer[0], pabyZlibBuffer[1]);
     282               0 :         CPLFree(pabyZlibBuffer);
     283               0 :         return CE_Failure;
     284                 :     }
     285                 : 
     286                 :     z_stream      stream;
     287             864 :     stream.zalloc = (alloc_func)0;
     288             864 :     stream.zfree = (free_func)0;
     289             864 :     stream.opaque = (voidpf)0;
     290             864 :     stream.next_in = pabyZlibBuffer + 2;
     291             864 :     stream.avail_in = nToRead - 2;
     292                 : 
     293             864 :     int err = inflateInit2(&(stream), -MAX_WBITS);
     294                 : 
     295                 :     int i;
     296           56160 :     for(i=0;i<64 && err == Z_OK;i++)
     297                 :     {
     298           55296 :         stream.next_out = (Bytef*)pImage + (63 - i) * 64;
     299           55296 :         stream.avail_out = 64;
     300           55296 :         err = inflate(& (stream), Z_NO_FLUSH);
     301           55296 :         if (err != Z_OK && err != Z_STREAM_END)
     302               0 :             break;
     303                 : 
     304           55296 :         if (pabyTranslationTable)
     305                 :         {
     306                 :             int j;
     307               0 :             GByte* ptr = ((GByte*)pImage) + (63 - i) * 64;
     308               0 :             for(j=0;j<64;j++)
     309                 :             {
     310               0 :                 *ptr = pabyTranslationTable[*ptr];
     311               0 :                 ptr ++;
     312                 :             }
     313                 :         }
     314                 :     }
     315                 : 
     316             864 :     inflateEnd(&stream);
     317                 : 
     318             864 :     CPLFree(pabyZlibBuffer);
     319                 : 
     320             864 :     return (err == Z_OK || err == Z_STREAM_END) ? CE_None : CE_Failure;
     321                 : }
     322                 : 
     323                 : /************************************************************************/
     324                 : /*                         GetOverviewCount()                            */
     325                 : /************************************************************************/
     326                 : 
     327               0 : int OZIRasterBand::GetOverviewCount()
     328                 : {
     329               0 :     if (nZoomLevel != 0)
     330               0 :         return 0;
     331                 : 
     332               0 :     OZIDataset *poGDS = (OZIDataset *) poDS;
     333               0 :     return poGDS->nZoomLevelCount - 1;
     334                 : }
     335                 : 
     336                 : /************************************************************************/
     337                 : /*                            GetOverview()                             */
     338                 : /************************************************************************/
     339                 : 
     340               0 : GDALRasterBand* OZIRasterBand::GetOverview(int nLevel)
     341                 : {
     342               0 :     if (nZoomLevel != 0)
     343               0 :         return NULL;
     344                 : 
     345               0 :     OZIDataset *poGDS = (OZIDataset *) poDS;
     346               0 :     if (nLevel < 0 || nLevel >= poGDS->nZoomLevelCount - 1)
     347               0 :         return NULL;
     348                 : 
     349               0 :     return poGDS->papoBands[nLevel + 1];
     350                 : }
     351                 : 
     352                 : /************************************************************************/
     353                 : /*                            ~OZIDataset()                            */
     354                 : /************************************************************************/
     355                 : 
     356               2 : OZIDataset::OZIDataset()
     357                 : {
     358               2 :     fp = NULL;
     359               2 :     nZoomLevelCount = 0;
     360               2 :     panZoomLevelOffsets = NULL;
     361               2 :     papoBands = NULL;
     362               2 :     bOzi3 = FALSE;
     363               2 :     nKeyInit = 0;
     364               2 :     adfGeoTransform[0] = 0;
     365               2 :     adfGeoTransform[1] = 1;
     366               2 :     adfGeoTransform[2] = 0;
     367               2 :     adfGeoTransform[3] = 0;
     368               2 :     adfGeoTransform[4] = 0;
     369               2 :     adfGeoTransform[5] = 1;
     370               2 :     pszWKT = NULL;
     371               2 :     nGCPCount = 0;
     372               2 :     pasGCPs = NULL;
     373               2 :     bReadMapFileSuccess = FALSE;
     374               2 : }
     375                 : 
     376                 : /************************************************************************/
     377                 : /*                            ~OZIDataset()                            */
     378                 : /************************************************************************/
     379                 : 
     380               2 : OZIDataset::~OZIDataset()
     381                 : {
     382               2 :     if (fp)
     383               2 :         VSIFCloseL(fp);
     384               2 :     CPLFree(panZoomLevelOffsets);
     385                 :     int i;
     386               2 :     if (papoBands)
     387                 :     {
     388              18 :         for(i=1;i<nZoomLevelCount;i++)
     389              16 :             delete papoBands[i];
     390               2 :         CPLFree(papoBands);
     391                 :     }
     392               2 :     CPLFree(pszWKT);
     393               2 :     if (nGCPCount)
     394                 :     {
     395               2 :         GDALDeinitGCPs( nGCPCount, pasGCPs );
     396               2 :         CPLFree(pasGCPs);
     397                 :     }
     398               2 : }
     399                 : 
     400                 : /************************************************************************/
     401                 : /*                             Identify()                               */
     402                 : /************************************************************************/
     403                 : 
     404           21506 : int OZIDataset::Identify( GDALOpenInfo * poOpenInfo )
     405                 : {
     406           21506 :     if (poOpenInfo->nHeaderBytes < 14)
     407           21138 :         return FALSE;
     408                 : 
     409             368 :     if (EQUALN((const char*)poOpenInfo->pabyHeader,
     410                 :         "OziExplorer Map Data File Version ", 34) )
     411               2 :         return TRUE;
     412                 : 
     413             366 :     if (poOpenInfo->pabyHeader[0] == 0x80 &&
     414               0 :         poOpenInfo->pabyHeader[1] == 0x77)
     415               0 :         return TRUE;
     416                 : 
     417             366 :     return poOpenInfo->pabyHeader[0] == 0x78 &&
     418               2 :            poOpenInfo->pabyHeader[1] == 0x77 &&
     419               2 :            poOpenInfo->pabyHeader[6] == 0x40 &&
     420               2 :            poOpenInfo->pabyHeader[7] == 0x00 &&
     421               2 :            poOpenInfo->pabyHeader[8] == 0x01 &&
     422               2 :            poOpenInfo->pabyHeader[9] == 0x00 &&
     423               2 :            poOpenInfo->pabyHeader[10] == 0x36 &&
     424               2 :            poOpenInfo->pabyHeader[11] == 0x04 &&
     425               2 :            poOpenInfo->pabyHeader[12] == 0x00 &&
     426             382 :            poOpenInfo->pabyHeader[13] == 0x00;
     427                 : }
     428                 : 
     429                 : /************************************************************************/
     430                 : /*                                Open()                                */
     431                 : /************************************************************************/
     432                 : 
     433            2610 : GDALDataset *OZIDataset::Open( GDALOpenInfo * poOpenInfo )
     434                 : 
     435                 : {
     436            2610 :     if (!Identify(poOpenInfo))
     437            2608 :         return NULL;
     438                 : 
     439                 :     GByte abyHeader[14];
     440               2 :     CPLString osImgFilename = poOpenInfo->pszFilename;
     441               2 :     int bIsMap = FALSE;
     442               2 :     if (EQUALN((const char*)poOpenInfo->pabyHeader,
     443                 :         "OziExplorer Map Data File Version ", 34) )
     444                 :     {
     445               2 :         char** papszLines = CSLLoad2( poOpenInfo->pszFilename, 1000, 200, NULL );
     446               2 :         if ( !papszLines || CSLCount(papszLines) < 5)
     447                 :         {
     448               0 :             CSLDestroy(papszLines);
     449               0 :             return FALSE;
     450                 :         }
     451                 : 
     452               2 :         bIsMap = TRUE;
     453                 : 
     454               2 :         osImgFilename = papszLines[2];
     455                 :         VSIStatBufL sStat;
     456               2 :         if (VSIStatL(osImgFilename, &sStat) != 0)
     457                 :         {
     458               2 :             if (CPLIsFilenameRelative(osImgFilename))
     459                 :             {
     460               2 :                 CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
     461               2 :                 osImgFilename = CPLFormFilename(osPath, osImgFilename, NULL);
     462                 :             }
     463                 :             else
     464                 :             {
     465               0 :                 CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
     466               0 :                 osImgFilename = CPLGetFilename(osImgFilename);
     467               0 :                 osImgFilename = CPLFormFilename(osPath, osImgFilename, NULL);
     468                 :             }
     469                 :         }
     470                 : 
     471               2 :         CSLDestroy(papszLines);
     472                 : 
     473               2 :         GDALOpenInfo oOpenInfo(osImgFilename, GA_ReadOnly);
     474               2 :         if (!Identify(&oOpenInfo))
     475               0 :             return NULL;
     476               2 :         memcpy(abyHeader, oOpenInfo.pabyHeader, 14);
     477                 :     }
     478                 :     else
     479               0 :         memcpy(abyHeader, poOpenInfo->pabyHeader, 14);
     480                 : 
     481               2 :     int bOzi3 = (abyHeader[0] == 0x80 &&
     482               2 :                  abyHeader[1] == 0x77);
     483                 : 
     484               2 :     VSILFILE* fp = VSIFOpenL(osImgFilename.c_str(), "rb");
     485               2 :     if (fp == NULL)
     486               0 :         return NULL;
     487                 : 
     488               2 :     OZIDataset* poDS = new OZIDataset();
     489               2 :     poDS->fp = fp;
     490                 : 
     491               2 :     if (bIsMap)
     492                 :     {
     493                 :         poDS->bReadMapFileSuccess =
     494                 :             GDALLoadOziMapFile( poOpenInfo->pszFilename,
     495                 :                                 poDS->adfGeoTransform,
     496                 :                                 &poDS->pszWKT,
     497                 :                                 &poDS->nGCPCount,
     498               2 :                                 &poDS->pasGCPs );
     499                 :     }
     500                 : 
     501               2 :     GByte nRandomNumber = 0;
     502               2 :     GByte nKeyInit = 0;
     503               2 :     if (bOzi3)
     504                 :     {
     505               0 :         VSIFSeekL(fp, 14, SEEK_SET);
     506               0 :         VSIFReadL(&nRandomNumber, 1, 1, fp);
     507                 :         //printf("nRandomNumber = %d\n", nRandomNumber);
     508               0 :         if (nRandomNumber < 0x94)
     509                 :         {
     510               0 :             delete poDS;
     511               0 :             return NULL;
     512                 :         }
     513               0 :         VSIFSeekL(fp, 0x93, SEEK_CUR);
     514               0 :         VSIFReadL(&nKeyInit, 1, 1, fp);
     515                 : 
     516               0 :         VSIFSeekL(fp, 0, SEEK_SET);
     517               0 :         VSIFReadL(abyHeader, 1, 14, fp);
     518               0 :         OZIDecrypt(abyHeader, 14, nKeyInit);
     519               0 :         if (!(abyHeader[6] == 0x40 &&
     520               0 :            abyHeader[7] == 0x00 &&
     521               0 :            abyHeader[8] == 0x01 &&
     522               0 :            abyHeader[9] == 0x00 &&
     523               0 :            abyHeader[10] == 0x36 &&
     524               0 :            abyHeader[11] == 0x04 &&
     525               0 :            abyHeader[12] == 0x00 &&
     526               0 :            abyHeader[13] == 0x00))
     527                 :         {
     528               0 :             delete poDS;
     529               0 :             return NULL;
     530                 :         }
     531                 : 
     532               0 :         VSIFSeekL(fp, 14 + 1 + nRandomNumber, SEEK_SET);
     533               0 :         int nMagic = ReadInt(fp, bOzi3, nKeyInit);
     534               0 :         CPLDebug("OZI", "OZI version code : 0x%08X", nMagic);
     535                 : 
     536               0 :         poDS->bOzi3 = bOzi3;
     537                 :     }
     538                 :     else
     539                 :     {
     540               2 :         VSIFSeekL(fp, 14, SEEK_SET);
     541                 :     }
     542                 : 
     543                 :     GByte abyHeader2[40], abyHeader2_Backup[40];
     544               2 :     VSIFReadL(abyHeader2, 40, 1, fp);
     545               2 :     memcpy(abyHeader2_Backup, abyHeader2, 40);
     546                 : 
     547                 :     /* There's apparently a relationship between the nMagic number */
     548                 :     /* and the nKeyInit, but I'm too lazy to add switch/cases that might */
     549                 :     /* be not exhaustive, so let's try the 'brute force' attack !!! */
     550                 :     /* It is much so funny to be able to run one in a few microseconds :-) */
     551               2 :     for(nKeyInit = 0; nKeyInit < 256; nKeyInit ++)
     552                 :     {
     553               2 :         GByte* pabyHeader2 = abyHeader2;
     554               2 :         if (bOzi3)
     555               0 :             OZIDecrypt(abyHeader2, 40, nKeyInit);
     556                 : 
     557               2 :         int nHeaderSize = ReadInt(&pabyHeader2); /* should be 40 */
     558               2 :         poDS->nRasterXSize = ReadInt(&pabyHeader2);
     559               2 :         poDS->nRasterYSize = ReadInt(&pabyHeader2);
     560               2 :         int nDepth = ReadShort(&pabyHeader2); /* should be 1 */
     561               2 :         int nBPP = ReadShort(&pabyHeader2); /* should be 8 */
     562               2 :         ReadInt(&pabyHeader2); /* reserved */
     563               2 :         ReadInt(&pabyHeader2); /* pixel number (height * width) : unused */
     564               2 :         ReadInt(&pabyHeader2); /* reserved */
     565               2 :         ReadInt(&pabyHeader2); /* reserved */
     566               2 :         ReadInt(&pabyHeader2); /* ?? 0x100 */
     567               2 :         ReadInt(&pabyHeader2); /* ?? 0x100 */
     568                 : 
     569               2 :         if (nHeaderSize != 40 || nDepth != 1 || nBPP != 8)
     570                 :         {
     571               0 :             if (bOzi3)
     572                 :             {
     573               0 :                 if (nKeyInit != 255)
     574                 :                 {
     575               0 :                     memcpy(abyHeader2, abyHeader2_Backup,40);
     576               0 :                     continue;
     577                 :                 }
     578                 :                 else
     579                 :                 {
     580               0 :                     CPLDebug("OZI", "Cannot decypher 2nd header. Sorry...");
     581               0 :                     delete poDS;
     582               0 :                     return NULL;
     583                 :                 }
     584                 :             }
     585                 :             else
     586                 :             {
     587                 :                 CPLDebug("OZI", "nHeaderSize = %d, nDepth = %d, nBPP = %d",
     588               0 :                         nHeaderSize, nDepth, nBPP);
     589               0 :                 delete poDS;
     590               0 :                 return NULL;
     591                 :             }
     592                 :         }
     593                 :         else
     594                 :             break;
     595                 :     }
     596               2 :     poDS->nKeyInit = nKeyInit;
     597                 : 
     598               2 :     int nSeparator = ReadInt(fp);
     599               2 :     if (!bOzi3 && nSeparator != 0x77777777)
     600                 :     {
     601               0 :         CPLDebug("OZI", "didn't get end of header2 marker");
     602               0 :         delete poDS;
     603               0 :         return NULL;
     604                 :     }
     605                 : 
     606               2 :     poDS->nZoomLevelCount = ReadShort(fp);
     607                 :     //CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
     608               2 :     if (poDS->nZoomLevelCount < 0 || poDS->nZoomLevelCount >= 256)
     609                 :     {
     610               0 :         CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
     611               0 :         delete poDS;
     612               0 :         return NULL;
     613                 :     }
     614                 : 
     615                 :     /* Skip array of zoom level percentage. We don't need it for GDAL */
     616               2 :     VSIFSeekL(fp, sizeof(float) * poDS->nZoomLevelCount, SEEK_CUR);
     617                 : 
     618               2 :     nSeparator = ReadInt(fp);
     619               2 :     if (!bOzi3 && nSeparator != 0x77777777)
     620                 :     {
     621                 :         /* Some files have 8 extra bytes before the marker. I'm not sure */
     622                 :         /* what they are used for. So just skeep them and hope that */
     623                 :         /* we'll find the marker */
     624               0 :         nSeparator = ReadInt(fp);
     625               0 :         nSeparator = ReadInt(fp);
     626               0 :         if (nSeparator != 0x77777777)
     627                 :         {
     628               0 :             CPLDebug("OZI", "didn't get end of zoom levels marker");
     629               0 :             delete poDS;
     630               0 :             return NULL;
     631                 :         }
     632                 :     }
     633                 : 
     634               2 :     VSIFSeekL(fp, 0, SEEK_END);
     635               2 :     vsi_l_offset nFileSize = VSIFTellL(fp);
     636               2 :     poDS->nFileSize = nFileSize;
     637               2 :     VSIFSeekL(fp, nFileSize - 4, SEEK_SET);
     638               2 :     int nZoomLevelTableOffset = ReadInt(fp, bOzi3, nKeyInit);
     639               2 :     if (nZoomLevelTableOffset < 0 ||
     640                 :         (vsi_l_offset)nZoomLevelTableOffset >= nFileSize)
     641                 :     {
     642                 :         CPLDebug("OZI", "nZoomLevelTableOffset = %d",
     643               0 :                  nZoomLevelTableOffset);
     644               0 :         delete poDS;
     645               0 :         return NULL;
     646                 :     }
     647                 : 
     648               2 :     VSIFSeekL(fp, nZoomLevelTableOffset, SEEK_SET);
     649                 : 
     650                 :     poDS->panZoomLevelOffsets =
     651               2 :         (int*)CPLMalloc(sizeof(int) * poDS->nZoomLevelCount);
     652                 :     int i;
     653              20 :     for(i=0;i<poDS->nZoomLevelCount;i++)
     654                 :     {
     655              18 :         poDS->panZoomLevelOffsets[i] = ReadInt(fp, bOzi3, nKeyInit);
     656              36 :         if (poDS->panZoomLevelOffsets[i] < 0 ||
     657              18 :             (vsi_l_offset)poDS->panZoomLevelOffsets[i] >= nFileSize)
     658                 :         {
     659                 :             CPLDebug("OZI", "panZoomLevelOffsets[%d] = %d",
     660               0 :                      i, poDS->panZoomLevelOffsets[i]);
     661               0 :             delete poDS;
     662               0 :             return NULL;
     663                 :         }
     664                 :     }
     665                 : 
     666                 :     poDS->papoBands =
     667               2 :         (OZIRasterBand**)CPLCalloc(sizeof(OZIRasterBand*), poDS->nZoomLevelCount);
     668                 : 
     669              20 :     for(i=0;i<poDS->nZoomLevelCount;i++)
     670                 :     {
     671              18 :         VSIFSeekL(fp, poDS->panZoomLevelOffsets[i], SEEK_SET);
     672              18 :         int nW = ReadInt(fp, bOzi3, nKeyInit);
     673              18 :         int nH = ReadInt(fp, bOzi3, nKeyInit);
     674              18 :         short nTileX = ReadShort(fp, bOzi3, nKeyInit);
     675              18 :         short nTileY = ReadShort(fp, bOzi3, nKeyInit);
     676              18 :         if (i == 0 && (nW != poDS->nRasterXSize || nH != poDS->nRasterYSize))
     677                 :         {
     678                 :             CPLDebug("OZI", "zoom[%d] inconsistant dimensions for zoom level 0 : nW=%d, nH=%d, nTileX=%d, nTileY=%d, nRasterXSize=%d, nRasterYSize=%d",
     679               0 :                      i, nW, nH, nTileX, nTileY, poDS->nRasterXSize, poDS->nRasterYSize);
     680               0 :             delete poDS;
     681               0 :             return NULL;
     682                 :         }
     683                 :         /* Note (#3895): some files such as world.ozf2 provided with OziExplorer */
     684                 :         /* expose nTileY=33, but have nH=2048, so only require 32 tiles in vertical dimension. */
     685                 :         /* So there's apparently one extra and useless tile that will be ignored */
     686                 :         /* without causing apparent issues */
     687                 :         /* Some other files have more tile in horizontal direction than needed, so let's */
     688                 :         /* accept that. But in that case we really need to keep the nTileX value for IReadBlock() */
     689                 :         /* to work properly */
     690              18 :         if ((nW + 63) / 64 > nTileX || (nH + 63) / 64 > nTileY)
     691                 :         {
     692                 :             CPLDebug("OZI", "zoom[%d] unexpected number of tiles : nW=%d, nH=%d, nTileX=%d, nTileY=%d",
     693               0 :                      i, nW, nH, nTileX, nTileY);
     694               0 :             delete poDS;
     695               0 :             return NULL;
     696                 :         }
     697                 : 
     698              18 :         GDALColorTable* poColorTable = new GDALColorTable();
     699                 :         GByte abyColorTable[256*4];
     700              18 :         VSIFReadL(abyColorTable, 1, 1024, fp);
     701              18 :         if (bOzi3)
     702               0 :             OZIDecrypt(abyColorTable, 1024, nKeyInit);
     703                 :         int j;
     704            4626 :         for(j=0;j<256;j++)
     705                 :         {
     706                 :             GDALColorEntry sEntry;
     707            4608 :             sEntry.c1 = abyColorTable[4*j + 2];
     708            4608 :             sEntry.c2 = abyColorTable[4*j + 1];
     709            4608 :             sEntry.c3 = abyColorTable[4*j + 0];
     710            4608 :             sEntry.c4 = 255;
     711            4608 :             poColorTable->SetColorEntry(j, &sEntry);
     712                 :         }
     713                 : 
     714              18 :         poDS->papoBands[i] = new OZIRasterBand(poDS, i, nW, nH, nTileX, poColorTable);
     715                 : 
     716              18 :         if (i > 0)
     717                 :         {
     718                 :             GByte* pabyTranslationTable =
     719              16 :                 poDS->papoBands[i]->GetIndexColorTranslationTo(poDS->papoBands[0], NULL, NULL);
     720                 : 
     721              16 :             delete poDS->papoBands[i]->poColorTable;
     722              16 :             poDS->papoBands[i]->poColorTable = poDS->papoBands[0]->poColorTable->Clone();
     723              16 :             poDS->papoBands[i]->pabyTranslationTable = pabyTranslationTable;
     724                 :         }
     725                 : 
     726                 :     }
     727                 : 
     728               2 :     poDS->SetBand(1, poDS->papoBands[0]);
     729                 : 
     730                 : /* -------------------------------------------------------------------- */
     731                 : /*      Initialize any PAM information.                                 */
     732                 : /* -------------------------------------------------------------------- */
     733               2 :     poDS->SetDescription( poOpenInfo->pszFilename );
     734               2 :     poDS->TryLoadXML();
     735                 : 
     736                 : /* -------------------------------------------------------------------- */
     737                 : /*      Support overviews.                                              */
     738                 : /* -------------------------------------------------------------------- */
     739               2 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     740               2 :     return( poDS );
     741                 : }
     742                 : 
     743                 : /************************************************************************/
     744                 : /*                          GetProjectionRef()                          */
     745                 : /************************************************************************/
     746                 : 
     747               0 : const char* OZIDataset::GetProjectionRef()
     748                 : {
     749               0 :     return (pszWKT && nGCPCount == 0) ? pszWKT : "";
     750                 : }
     751                 : 
     752                 : /************************************************************************/
     753                 : /*                          GetGeoTransform()                           */
     754                 : /************************************************************************/
     755                 : 
     756               0 : CPLErr OZIDataset::GetGeoTransform( double * padfTransform )
     757                 : 
     758                 : {
     759               0 :     memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
     760                 : 
     761               0 :     return( (bReadMapFileSuccess && nGCPCount == 0) ? CE_None : CE_Failure );
     762                 : }
     763                 : 
     764                 : /************************************************************************/
     765                 : /*                           GetGCPCount()                              */
     766                 : /************************************************************************/
     767                 : 
     768               2 : int OZIDataset::GetGCPCount()
     769                 : {
     770               2 :     return nGCPCount;
     771                 : }
     772                 : 
     773                 : /************************************************************************/
     774                 : /*                          GetGCPProjection()                          */
     775                 : /************************************************************************/
     776                 : 
     777               2 : const char * OZIDataset::GetGCPProjection()
     778                 : {
     779               2 :     return (pszWKT && nGCPCount != 0) ? pszWKT : "";
     780                 : }
     781                 : 
     782                 : /************************************************************************/
     783                 : /*                               GetGCPs()                              */
     784                 : /************************************************************************/
     785                 : 
     786               2 : const GDAL_GCP * OZIDataset::GetGCPs()
     787                 : {
     788               2 :     return pasGCPs;
     789                 : }
     790                 : 
     791                 : /************************************************************************/
     792                 : /*                         GDALRegister_OZI()                           */
     793                 : /************************************************************************/
     794                 : 
     795            1135 : void GDALRegister_OZI()
     796                 : 
     797                 : {
     798                 :     GDALDriver  *poDriver;
     799                 : 
     800            1135 :     if (! GDAL_CHECK_VERSION("OZI driver"))
     801               0 :         return;
     802                 : 
     803            1135 :     if( GDALGetDriverByName( "OZI" ) == NULL )
     804                 :     {
     805            1093 :         poDriver = new GDALDriver();
     806                 : 
     807            1093 :         poDriver->SetDescription( "OZI" );
     808                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
     809            1093 :                                    "OziExplorer Image File" );
     810                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
     811            1093 :                                    "frmt_ozi.html" );
     812                 : 
     813            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     814                 : 
     815            1093 :         poDriver->pfnOpen = OZIDataset::Open;
     816            1093 :         poDriver->pfnIdentify = OZIDataset::Identify;
     817                 : 
     818            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     819                 :     }
     820                 : }
     821                 : 

Generated by: LCOV version 1.7