LCOV - code coverage report
Current view: directory - frmts/raw - pnmdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 147 128 87.1 %
Date: 2012-12-26 Functions: 10 7 70.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: pnmdataset.cpp 21696 2011-02-12 20:35:50Z rouault $
       3                 :  *
       4                 :  * Project:  PNM Driver
       5                 :  * Purpose:  Portable anymap file format imlementation
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2001, Frank Warmerdam
      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 "rawdataset.h"
      31                 : #include "cpl_string.h"
      32                 : #include <ctype.h>
      33                 : 
      34                 : CPL_CVSID("$Id: pnmdataset.cpp 21696 2011-02-12 20:35:50Z rouault $");
      35                 : 
      36                 : CPL_C_START
      37                 : void    GDALRegister_PNM(void);
      38                 : CPL_C_END
      39                 : 
      40                 : /************************************************************************/
      41                 : /* ==================================================================== */
      42                 : /*                              PNMDataset                              */
      43                 : /* ==================================================================== */
      44                 : /************************************************************************/
      45                 : 
      46                 : class PNMDataset : public RawDataset
      47                 : {
      48                 :     VSILFILE        *fpImage;       // image data file.
      49                 : 
      50                 :     int         bGeoTransformValid;
      51                 :     double      adfGeoTransform[6];
      52                 : 
      53                 :   public:
      54                 :                 PNMDataset();
      55                 :                 ~PNMDataset();
      56                 : 
      57                 :     virtual CPLErr GetGeoTransform( double * );
      58                 : 
      59                 :     static int          Identify( GDALOpenInfo * );
      60                 :     static GDALDataset *Open( GDALOpenInfo * );
      61                 :     static GDALDataset *Create( const char * pszFilename,
      62                 :                                 int nXSize, int nYSize, int nBands,
      63                 :                                 GDALDataType eType, char ** papszOptions );
      64                 : };
      65                 : 
      66                 : /************************************************************************/
      67                 : /*                            PNMDataset()                             */
      68                 : /************************************************************************/
      69                 : 
      70              49 : PNMDataset::PNMDataset()
      71                 : {
      72              49 :     fpImage = NULL;
      73              49 :     bGeoTransformValid = FALSE;
      74              49 :     adfGeoTransform[0] = 0.0;
      75              49 :     adfGeoTransform[1] = 1.0;
      76              49 :     adfGeoTransform[2] = 0.0;
      77              49 :     adfGeoTransform[3] = 0.0;
      78              49 :     adfGeoTransform[4] = 0.0;
      79              49 :     adfGeoTransform[5] = 1.0;
      80              49 : }
      81                 : 
      82                 : /************************************************************************/
      83                 : /*                            ~PNMDataset()                            */
      84                 : /************************************************************************/
      85                 : 
      86              49 : PNMDataset::~PNMDataset()
      87                 : 
      88                 : {
      89              49 :     FlushCache();
      90              49 :     if( fpImage != NULL )
      91              49 :         VSIFCloseL( fpImage );
      92              49 : }
      93                 : 
      94                 : /************************************************************************/
      95                 : /*                          GetGeoTransform()                           */
      96                 : /************************************************************************/
      97                 : 
      98               4 : CPLErr PNMDataset::GetGeoTransform( double * padfTransform )
      99                 : 
     100                 : {
     101                 : 
     102               4 :     if( bGeoTransformValid )
     103                 :     {
     104               0 :         memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
     105               0 :         return CE_None;
     106                 :     }
     107                 :     else
     108               4 :         return CE_Failure;
     109                 : }
     110                 : 
     111                 : /************************************************************************/
     112                 : /*                              Identify()                              */
     113                 : /************************************************************************/
     114                 : 
     115           12389 : int PNMDataset::Identify( GDALOpenInfo * poOpenInfo )
     116                 : 
     117                 : {
     118                 : /* -------------------------------------------------------------------- */
     119                 : /*      Verify that this is a _raw_ ppm or pgm file.  Note, we don't    */
     120                 : /*      support ascii files, or pbm (1bit) files.                       */
     121                 : /* -------------------------------------------------------------------- */
     122           12389 :     if( poOpenInfo->nHeaderBytes < 10 )
     123           11530 :         return FALSE;
     124                 : 
     125            1034 :     if( poOpenInfo->pabyHeader[0] != 'P'  ||
     126              56 :         (poOpenInfo->pabyHeader[2] != ' '  &&    // XXX: Magick number
     127              56 :          poOpenInfo->pabyHeader[2] != '\t' &&    // may be followed
     128              56 :          poOpenInfo->pabyHeader[2] != '\n' &&    // any of the blank
     129               7 :          poOpenInfo->pabyHeader[2] != '\r') )    // characters
     130             810 :         return FALSE;
     131                 : 
     132              67 :     if( poOpenInfo->pabyHeader[1] != '5'
     133              18 :         && poOpenInfo->pabyHeader[1] != '6' )
     134               0 :         return FALSE;
     135                 : 
     136              49 :     return TRUE;
     137                 : }
     138                 : 
     139                 : /************************************************************************/
     140                 : /*                                Open()                                */
     141                 : /************************************************************************/
     142                 : 
     143            2296 : GDALDataset *PNMDataset::Open( GDALOpenInfo * poOpenInfo )
     144                 : 
     145                 : {
     146                 : /* -------------------------------------------------------------------- */
     147                 : /*      Verify that this is a _raw_ ppm or pgm file.  Note, we don't    */
     148                 : /*      support ascii files, or pbm (1bit) files.                       */
     149                 : /* -------------------------------------------------------------------- */
     150            2296 :     if( !Identify( poOpenInfo ) )
     151            2247 :         return NULL;
     152                 : 
     153                 : /* -------------------------------------------------------------------- */
     154                 : /*      Parse out the tokens from the header.                           */
     155                 : /* -------------------------------------------------------------------- */
     156              49 :     const char  *pszSrc = (const char *) poOpenInfo->pabyHeader;
     157                 :     char        szToken[512];
     158              49 :     int         iIn, iToken = 0, nWidth =-1, nHeight=-1, nMaxValue=-1;
     159                 :     unsigned int iOut;
     160                 : 
     161              49 :     iIn = 2;
     162             245 :     while( iIn < poOpenInfo->nHeaderBytes && iToken < 3 )
     163                 :     {
     164             147 :         iOut = 0;
     165             147 :         szToken[0] = '\0';
     166             737 :         while( iOut < sizeof(szToken) && iIn < poOpenInfo->nHeaderBytes )
     167                 :         {
     168             590 :             if( pszSrc[iIn] == '#' )
     169                 :             {
     170               0 :                 while( pszSrc[iIn] != 10 && pszSrc[iIn] != 13
     171                 :                        && iIn < poOpenInfo->nHeaderBytes - 1 )
     172               0 :                     iIn++;
     173                 :             }
     174                 : 
     175             590 :             if( iOut != 0 && isspace((unsigned char)pszSrc[iIn]) )
     176                 :             {
     177             147 :                 szToken[iOut] = '\0';
     178                 : 
     179             147 :                 if( iToken == 0 )
     180              49 :                     nWidth = atoi(szToken);
     181              98 :                 else if( iToken == 1 )
     182              49 :                     nHeight = atoi(szToken);
     183              49 :                 else if( iToken == 2 )
     184              49 :                     nMaxValue = atoi(szToken);
     185                 : 
     186             147 :                 iToken++;
     187             147 :                 iIn++;
     188             147 :                 break;
     189                 :             }
     190                 : 
     191             443 :             else if( !isspace((unsigned char)pszSrc[iIn]) )
     192                 :             {
     193             394 :                 szToken[iOut++] = pszSrc[iIn];
     194                 :             }
     195                 : 
     196             443 :             iIn++;
     197                 :         }
     198                 :     }
     199                 : 
     200                 :     CPLDebug( "PNM", "PNM header contains: width=%d, height=%d, maxval=%d",
     201              49 :               nWidth, nHeight, nMaxValue );
     202                 : 
     203              49 :     if( iToken != 3 || nWidth < 1 || nHeight < 1 || nMaxValue < 1 )
     204               0 :         return NULL;
     205                 : 
     206                 : /* -------------------------------------------------------------------- */
     207                 : /*      Create a corresponding GDALDataset.                             */
     208                 : /* -------------------------------------------------------------------- */
     209                 :     PNMDataset  *poDS;
     210                 : 
     211              49 :     poDS = new PNMDataset();
     212                 : 
     213                 : /* -------------------------------------------------------------------- */
     214                 : /*      Capture some information from the file that is of interest.     */
     215                 : /* -------------------------------------------------------------------- */
     216              49 :     poDS->nRasterXSize = nWidth;
     217              49 :     poDS->nRasterYSize = nHeight;
     218                 : 
     219                 : /* -------------------------------------------------------------------- */
     220                 : /*      Open file                                                       */
     221                 : /* -------------------------------------------------------------------- */
     222                 : 
     223              49 :     if( poOpenInfo->eAccess == GA_Update )
     224              17 :         poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
     225                 :     else
     226              32 :         poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     227                 : 
     228              49 :     if( poDS->fpImage == NULL )
     229                 :     {
     230                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     231                 :                   "Failed to re-open %s within PNM driver.\n",
     232               0 :                   poOpenInfo->pszFilename );
     233               0 :         return NULL;
     234                 :     }
     235                 : 
     236              49 :     poDS->eAccess = poOpenInfo->eAccess;
     237                 : 
     238                 : /* -------------------------------------------------------------------- */
     239                 : /*      Create band information objects.                                */
     240                 : /* -------------------------------------------------------------------- */
     241              49 :     int         bMSBFirst = TRUE, iPixelSize;
     242                 :     GDALDataType eDataType;
     243                 : 
     244                 : #ifdef CPL_LSB
     245              49 :     bMSBFirst = FALSE;
     246                 : #endif
     247                 : 
     248              49 :     if ( nMaxValue < 256 )
     249              37 :         eDataType = GDT_Byte;
     250                 :     else
     251              12 :         eDataType = GDT_UInt16;
     252                 : 
     253              49 :     iPixelSize = GDALGetDataTypeSize( eDataType ) / 8;
     254                 : 
     255              49 :     if( poOpenInfo->pabyHeader[1] == '5' )
     256                 :     {
     257              31 :         if (nWidth > INT_MAX / iPixelSize)
     258                 :         {
     259                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     260               0 :                   "Int overflow occured.");
     261               0 :             delete poDS;
     262               0 :             return NULL;
     263                 :         }
     264                 :         poDS->SetBand(
     265                 :             1, new RawRasterBand( poDS, 1, poDS->fpImage, iIn, iPixelSize,
     266              31 :                                   nWidth*iPixelSize, eDataType, bMSBFirst, TRUE ));
     267              31 :         poDS->GetRasterBand(1)->SetColorInterpretation( GCI_GrayIndex );
     268                 :     }
     269                 :     else
     270                 :     {
     271              18 :         if (nWidth > INT_MAX / (3 * iPixelSize))
     272                 :         {
     273                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     274               0 :                   "Int overflow occured.");
     275               0 :             delete poDS;
     276               0 :             return NULL;
     277                 :         }
     278                 :         poDS->SetBand(
     279                 :             1, new RawRasterBand( poDS, 1, poDS->fpImage, iIn, 3*iPixelSize,
     280              18 :                                   nWidth*3*iPixelSize, eDataType, bMSBFirst, TRUE ));
     281                 :         poDS->SetBand(
     282                 :             2, new RawRasterBand( poDS, 2, poDS->fpImage, iIn+iPixelSize,
     283                 :                                   3*iPixelSize, nWidth*3*iPixelSize,
     284              36 :                                   eDataType, bMSBFirst, TRUE ));
     285                 :         poDS->SetBand(
     286                 :             3, new RawRasterBand( poDS, 3, poDS->fpImage, iIn+2*iPixelSize,
     287                 :                                   3*iPixelSize, nWidth*3*iPixelSize,
     288              36 :                                   eDataType, bMSBFirst, TRUE ));
     289                 : 
     290              18 :         poDS->GetRasterBand(1)->SetColorInterpretation( GCI_RedBand );
     291              18 :         poDS->GetRasterBand(2)->SetColorInterpretation( GCI_GreenBand );
     292              18 :         poDS->GetRasterBand(3)->SetColorInterpretation( GCI_BlueBand );
     293                 :     }
     294                 : 
     295                 : /* -------------------------------------------------------------------- */
     296                 : /*      Check for world file.                                           */
     297                 : /* -------------------------------------------------------------------- */
     298                 :     poDS->bGeoTransformValid = 
     299                 :         GDALReadWorldFile( poOpenInfo->pszFilename, ".wld", 
     300              49 :                            poDS->adfGeoTransform );
     301                 : 
     302                 : /* -------------------------------------------------------------------- */
     303                 : /*      Initialize any PAM information.                                 */
     304                 : /* -------------------------------------------------------------------- */
     305              49 :     poDS->SetDescription( poOpenInfo->pszFilename );
     306              49 :     poDS->TryLoadXML();
     307                 : 
     308                 : /* -------------------------------------------------------------------- */
     309                 : /*      Check for overviews.                                            */
     310                 : /* -------------------------------------------------------------------- */
     311              49 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     312                 : 
     313              49 :     return( poDS );
     314                 : }
     315                 : 
     316                 : /************************************************************************/
     317                 : /*                               Create()                               */
     318                 : /************************************************************************/
     319                 : 
     320              55 : GDALDataset *PNMDataset::Create( const char * pszFilename,
     321                 :                                  int nXSize, int nYSize, int nBands,
     322                 :                                  GDALDataType eType,
     323                 :                                  char ** papszOptions )
     324                 : 
     325                 : {
     326                 : /* -------------------------------------------------------------------- */
     327                 : /*      Verify input options.                                           */
     328                 : /* -------------------------------------------------------------------- */
     329              55 :     if( eType != GDT_Byte && eType != GDT_UInt16 )
     330                 :     {
     331                 :         CPLError( CE_Failure, CPLE_AppDefined,
     332                 :               "Attempt to create PNM dataset with an illegal\n"
     333                 :               "data type (%s), only Byte and UInt16 supported.\n",
     334              27 :               GDALGetDataTypeName(eType) );
     335                 : 
     336              27 :         return NULL;
     337                 :     }
     338                 : 
     339              28 :     if( nBands != 1 && nBands != 3 )
     340                 :     {
     341                 :         CPLError( CE_Failure, CPLE_AppDefined,
     342                 :                   "Attempt to create PNM dataset with an illegal number\n"
     343                 :                   "of bands (%d).  Must be 1 (greyscale) or 3 (RGB).\n",
     344               7 :                   nBands );
     345                 : 
     346               7 :         return NULL;
     347                 :     }
     348                 : 
     349                 : /* -------------------------------------------------------------------- */
     350                 : /*      Try to create the file.                                         */
     351                 : /* -------------------------------------------------------------------- */
     352                 :     VSILFILE        *fp;
     353                 : 
     354              21 :     fp = VSIFOpenL( pszFilename, "wb" );
     355                 : 
     356              21 :     if( fp == NULL )
     357                 :     {
     358                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     359                 :                   "Attempt to create file `%s' failed.\n",
     360               5 :                   pszFilename );
     361               5 :         return NULL;
     362                 :     }
     363                 : 
     364                 : /* -------------------------------------------------------------------- */
     365                 : /*      Write out the header.                                           */
     366                 : /* -------------------------------------------------------------------- */
     367                 :     char        szHeader[500];
     368              16 :     const char  *pszMaxValue = NULL;
     369              16 :     int         nMaxValue = 0;
     370                 : 
     371              16 :     pszMaxValue = CSLFetchNameValue( papszOptions, "MAXVAL" );
     372              16 :     if ( pszMaxValue )
     373                 :     {
     374               0 :         nMaxValue = atoi( pszMaxValue );
     375               0 :         if ( eType == GDT_Byte && (nMaxValue > 255 || nMaxValue < 0) )
     376               0 :             nMaxValue = 255;
     377               0 :         else if ( nMaxValue > 65535 || nMaxValue < 0 )
     378               0 :             nMaxValue = 65535;
     379                 :     }
     380                 :     else
     381                 :     {
     382              16 :         if ( eType == GDT_Byte )
     383              11 :             nMaxValue = 255;
     384                 :         else
     385               5 :             nMaxValue = 65535;
     386                 :     }
     387                 : 
     388                 : 
     389              16 :     memset( szHeader, 0, sizeof(szHeader) );
     390                 : 
     391              16 :     if( nBands == 3 )
     392               5 :         sprintf( szHeader, "P6\n%d %d\n%d\n", nXSize, nYSize, nMaxValue );
     393                 :     else
     394              11 :         sprintf( szHeader, "P5\n%d %d\n%d\n", nXSize, nYSize, nMaxValue );
     395                 : 
     396              16 :     VSIFWriteL( (void *) szHeader, strlen(szHeader) + 2, 1, fp );
     397              16 :     VSIFCloseL( fp );
     398                 : 
     399              16 :     return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
     400                 : }
     401                 : 
     402                 : /************************************************************************/
     403                 : /*                         GDALRegister_PNM()                          */
     404                 : /************************************************************************/
     405                 : 
     406             582 : void GDALRegister_PNM()
     407                 : 
     408                 : {
     409                 :     GDALDriver  *poDriver;
     410                 : 
     411             582 :     if( GDALGetDriverByName( "PNM" ) == NULL )
     412                 :     {
     413             561 :         poDriver = new GDALDriver();
     414                 : 
     415             561 :         poDriver->SetDescription( "PNM" );
     416                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
     417             561 :                                    "Portable Pixmap Format (netpbm)" );
     418                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
     419             561 :                                    "frmt_various.html#PNM" );
     420             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "pnm" );
     421                 :         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE,
     422             561 :                                    "image/x-portable-anymap" );
     423                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
     424             561 :                                    "Byte UInt16" );
     425                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
     426                 : "<CreationOptionList>"
     427                 : "   <Option name='MAXVAL' type='unsigned int' description='Maximum color value'/>"
     428             561 : "</CreationOptionList>" );
     429             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     430                 : 
     431             561 :         poDriver->pfnOpen = PNMDataset::Open;
     432             561 :         poDriver->pfnCreate = PNMDataset::Create;
     433             561 :         poDriver->pfnIdentify = PNMDataset::Identify;
     434                 : 
     435             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     436                 :     }
     437             582 : }

Generated by: LCOV version 1.7