LCOV - code coverage report
Current view: directory - frmts/xpm - xpmdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 227 183 80.6 %
Date: 2012-12-26 Functions: 9 6 66.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: xpmdataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $
       3                 :  *
       4                 :  * Project:  XPM Driver
       5                 :  * Purpose:  Implement GDAL XPM Support
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2002, 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 "gdal_pam.h"
      31                 : #include "cpl_string.h"
      32                 : #include "memdataset.h"
      33                 : #include "gdal_frmts.h"                 
      34                 : 
      35                 : 
      36                 : CPL_CVSID("$Id: xpmdataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $");
      37                 : 
      38                 : static unsigned char *ParseXPM( const char *pszInput,
      39                 :                                 int *pnXSize, int *pnYSize, 
      40                 :                                 GDALColorTable **ppoRetTable );
      41                 : 
      42                 : 
      43                 : /************************************************************************/
      44                 : /* ==================================================================== */
      45                 : /*        XPMDataset        */
      46                 : /* ==================================================================== */
      47                 : /************************************************************************/
      48                 : 
      49                 : class XPMDataset : public GDALPamDataset
      50                 : {
      51                 :   public:
      52                 :                  XPMDataset();
      53                 :                  ~XPMDataset();
      54                 : 
      55                 :     static GDALDataset *Open( GDALOpenInfo * );
      56                 : };
      57                 : 
      58                 : /************************************************************************/
      59                 : /*                            XPMDataset()                            */
      60                 : /************************************************************************/
      61                 : 
      62               2 : XPMDataset::XPMDataset()
      63                 : 
      64                 : {
      65               2 : }
      66                 : 
      67                 : /************************************************************************/
      68                 : /*                            ~XPMDataset()                             */
      69                 : /************************************************************************/
      70                 : 
      71               2 : XPMDataset::~XPMDataset()
      72                 : 
      73                 : {
      74               2 :     FlushCache();
      75               2 : }
      76                 : 
      77                 : /************************************************************************/
      78                 : /*                                Open()                                */
      79                 : /************************************************************************/
      80                 : 
      81           13657 : GDALDataset *XPMDataset::Open( GDALOpenInfo * poOpenInfo )
      82                 : 
      83                 : {
      84                 : /* -------------------------------------------------------------------- */
      85                 : /*      First we check to see if the file has the expected header       */
      86                 : /*      bytes.  For now we expect the XPM file to start with a line     */
      87                 : /*      containing the letters XPM, and to have "static" in the         */
      88                 : /*      header.                                                         */
      89                 : /* -------------------------------------------------------------------- */
      90           13657 :     if( poOpenInfo->nHeaderBytes < 32 
      91                 :         || strstr((const char *) poOpenInfo->pabyHeader,"XPM") == NULL 
      92                 :         || strstr((const char *) poOpenInfo->pabyHeader,"static") == NULL )
      93           13655 :         return NULL;
      94                 : 
      95               2 :     if( poOpenInfo->eAccess == GA_Update )
      96                 :     {
      97                 :         CPLError( CE_Failure, CPLE_NotSupported, 
      98                 :                   "The XPM driver does not support update access to existing"
      99               0 :                   " files." );
     100               0 :         return NULL;
     101                 :     }
     102                 : 
     103                 : /* -------------------------------------------------------------------- */
     104                 : /*      Read the whole file into a memory strings.                      */
     105                 : /* -------------------------------------------------------------------- */
     106                 :     unsigned int nFileSize;
     107                 :     char *pszFileContents;
     108               2 :     VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     109               2 :     if( fp == NULL )
     110               0 :         return NULL;
     111                 : 
     112               2 :     VSIFSeekL( fp, 0, SEEK_END );
     113               2 :     nFileSize = (unsigned int) VSIFTellL( fp );
     114                 :     
     115               2 :     pszFileContents = (char *) VSIMalloc(nFileSize+1);
     116               2 :     if( pszFileContents == NULL )
     117                 :     {
     118                 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
     119                 :                   "Insufficient memory for loading XPM file %s into memory.", 
     120               0 :                   poOpenInfo->pszFilename );
     121               0 :         VSIFCloseL(fp);
     122               0 :         return NULL;
     123                 :     }
     124               2 :     pszFileContents[nFileSize] = '\0';
     125                 :     
     126               2 :     VSIFSeekL( fp, 0, SEEK_SET );
     127                 : 
     128               2 :     if( VSIFReadL( pszFileContents, 1, nFileSize, fp ) != nFileSize)
     129                 :     {
     130               0 :         CPLFree( pszFileContents );
     131                 :         CPLError( CE_Failure, CPLE_FileIO, 
     132                 :                   "Failed to read all %d bytes from file %s.",
     133               0 :                   nFileSize, poOpenInfo->pszFilename );
     134               0 :         VSIFCloseL(fp);
     135               0 :         return NULL;
     136                 :     }
     137                 :     
     138               2 :     VSIFCloseL(fp);
     139               2 :     fp = NULL;
     140                 : 
     141                 : /* -------------------------------------------------------------------- */
     142                 : /*      Convert into a binary image.                                    */
     143                 : /* -------------------------------------------------------------------- */
     144                 :     GByte *pabyImage;
     145                 :     int   nXSize, nYSize;
     146               2 :     GDALColorTable *poCT = NULL;
     147                 : 
     148               2 :     CPLErrorReset();
     149                 : 
     150               2 :     pabyImage = ParseXPM( pszFileContents, &nXSize, &nYSize, &poCT );
     151               2 :     CPLFree( pszFileContents );
     152                 : 
     153               2 :     if( pabyImage == NULL )
     154                 :     {
     155               0 :         return NULL;
     156                 :     }
     157                 : 
     158                 : /* -------------------------------------------------------------------- */
     159                 : /*      Create a corresponding GDALDataset.                             */
     160                 : /* -------------------------------------------------------------------- */
     161                 :     XPMDataset  *poDS;
     162                 : 
     163               2 :     poDS = new XPMDataset();
     164                 : 
     165                 : /* -------------------------------------------------------------------- */
     166                 : /*      Capture some information from the file that is of interest.     */
     167                 : /* -------------------------------------------------------------------- */
     168               2 :     poDS->nRasterXSize = nXSize;
     169               2 :     poDS->nRasterYSize = nYSize;
     170                 : 
     171                 : /* -------------------------------------------------------------------- */
     172                 : /*      Create band information objects.                                */
     173                 : /* -------------------------------------------------------------------- */
     174                 :     MEMRasterBand *poBand;
     175                 : 
     176                 :     poBand = new MEMRasterBand( poDS, 1, pabyImage, GDT_Byte, 1, nXSize, 
     177               4 :                                 TRUE );
     178               2 :     poBand->SetColorTable( poCT );
     179               2 :     poDS->SetBand( 1, poBand );
     180                 : 
     181               4 :     delete poCT;
     182                 : 
     183                 : /* -------------------------------------------------------------------- */
     184                 : /*      Initialize any PAM information.                                 */
     185                 : /* -------------------------------------------------------------------- */
     186               2 :     poDS->SetDescription( poOpenInfo->pszFilename );
     187               2 :     poDS->TryLoadXML();
     188                 : 
     189                 : /* -------------------------------------------------------------------- */
     190                 : /*      Support overviews.                                              */
     191                 : /* -------------------------------------------------------------------- */
     192               2 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     193                 : 
     194               2 :     return poDS;
     195                 : }
     196                 : 
     197                 : /************************************************************************/
     198                 : /*                           XPMCreateCopy()                            */
     199                 : /************************************************************************/
     200                 : 
     201                 : static GDALDataset *
     202              18 : XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     203                 :                int bStrict, char ** papszOptions, 
     204                 :                GDALProgressFunc pfnProgress, void * pProgressData )
     205                 : 
     206                 : {
     207              18 :     int  nBands = poSrcDS->GetRasterCount();
     208              18 :     int  nXSize = poSrcDS->GetRasterXSize();
     209              18 :     int  nYSize = poSrcDS->GetRasterYSize();
     210                 :     GDALColorTable *poCT;
     211                 : 
     212                 : /* -------------------------------------------------------------------- */
     213                 : /*      Some some rudimentary checks                                    */
     214                 : /* -------------------------------------------------------------------- */
     215              18 :     if( nBands != 1 )
     216                 :     {
     217                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     218               5 :                   "XPM driver only supports one band images.\n" );
     219                 : 
     220               5 :         return NULL;
     221                 :     }
     222                 : 
     223              13 :     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
     224                 :         && bStrict )
     225                 :     {
     226                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     227                 :                   "XPM driver doesn't support data type %s. "
     228                 :                   "Only eight bit bands supported.\n", 
     229                 :                   GDALGetDataTypeName( 
     230              10 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
     231                 : 
     232              10 :         return NULL;
     233                 :     }
     234                 : 
     235                 : /* -------------------------------------------------------------------- */
     236                 : /*      If there is no colortable on the source image, create a         */
     237                 : /*      greyscale one with 64 levels of grey.                           */
     238                 : /* -------------------------------------------------------------------- */
     239               3 :     GDALRasterBand  *poBand = poSrcDS->GetRasterBand(1);
     240                 :     int                 i;
     241               3 :     GDALColorTable      oGreyTable;
     242                 : 
     243               3 :     poCT = poBand->GetColorTable();
     244               3 :     if( poCT == NULL )
     245                 :     {
     246               3 :         poCT = &oGreyTable;
     247                 : 
     248             771 :         for( i = 0; i < 256; i++ )
     249                 :         {
     250                 :             GDALColorEntry sColor;
     251                 : 
     252             768 :             sColor.c1 = (short) i;
     253             768 :             sColor.c2 = (short) i;
     254             768 :             sColor.c3 = (short) i;
     255             768 :             sColor.c4 = 255;
     256                 : 
     257             768 :             poCT->SetColorEntry( i, &sColor );
     258                 :         }
     259                 :     }
     260                 : 
     261                 : /* -------------------------------------------------------------------- */
     262                 : /*      Build list of active colors, and the mapping from pixels to     */
     263                 : /*      our active colormap.                                            */
     264                 : /* -------------------------------------------------------------------- */
     265               3 :     const char *pszColorCodes = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+=[]|:;,.<>?/";
     266                 : 
     267                 :     int  anPixelMapping[256];
     268                 :     GDALColorEntry asPixelColor[256];
     269               3 :     int  nActiveColors = MIN(poCT->GetColorEntryCount(),256);
     270                 : 
     271                 :     // Setup initial colortable and pixel value mapping. 
     272               3 :     memset( anPixelMapping+0, 0, sizeof(int) * 256 );
     273             771 :     for( i = 0; i < nActiveColors; i++ )
     274                 :     {
     275             768 :         poCT->GetColorEntryAsRGB( i, asPixelColor + i );
     276             768 :         anPixelMapping[i] = i;
     277                 :     }
     278                 : 
     279                 : /* ==================================================================== */
     280                 : /*      Iterate merging colors until we are under our limit (about 85). */
     281                 : /* ==================================================================== */
     282             513 :     while( nActiveColors > (int) strlen(pszColorCodes) )
     283                 :     {
     284             507 :         int nClosestDistance = 768;
     285             507 :         int iClose1 = -1, iClose2 = -1;
     286                 :         int iColor1, iColor2;
     287                 : 
     288                 :         // Find the closest pair of colors. 
     289           21675 :         for( iColor1 = 0; iColor1 < nActiveColors; iColor1++ )
     290                 :         {
     291         2521440 :             for( iColor2 = iColor1+1; iColor2 < nActiveColors; iColor2++ )
     292                 :             {
     293                 :                 int nDistance;
     294                 : 
     295         2499765 :                 if( asPixelColor[iColor1].c4 < 128 
     296                 :                     && asPixelColor[iColor2].c4 < 128 )
     297               0 :                     nDistance = 0;
     298                 :                 else
     299                 :                     nDistance = 
     300                 :                         ABS(asPixelColor[iColor1].c1-asPixelColor[iColor2].c1)
     301                 :                       + ABS(asPixelColor[iColor1].c2-asPixelColor[iColor2].c2)
     302         2499765 :                       + ABS(asPixelColor[iColor1].c3-asPixelColor[iColor2].c3);
     303                 : 
     304         2499765 :                 if( nDistance < nClosestDistance )
     305                 :                 {
     306            2097 :                     nClosestDistance = nDistance;
     307            2097 :                     iClose1 = iColor1;
     308            2097 :                     iClose2 = iColor2;
     309                 :                 }
     310                 :             }
     311                 : 
     312           21675 :             if( nClosestDistance < 8 )
     313             507 :                 break;
     314                 :         }
     315                 : 
     316                 :         // This should never happen!
     317             507 :         if( iClose1 == -1 )
     318               0 :             break;
     319                 : 
     320                 :         // Merge two selected colors - shift icolor2 into icolor1 and
     321                 :         // move the last active color into icolor2's slot. 
     322          130299 :         for( i = 0; i < 256; i++ )
     323                 :         {
     324          129792 :             if( anPixelMapping[i] == iClose2 )
     325             507 :                 anPixelMapping[i] = iClose1;
     326          129285 :             else if( anPixelMapping[i] == nActiveColors-1 )
     327             339 :                 anPixelMapping[i] = iClose2;
     328                 :         }
     329                 : 
     330             507 :         asPixelColor[iClose2] = asPixelColor[nActiveColors-1];
     331             507 :         nActiveColors--;
     332                 :     }
     333                 :         
     334                 : /* ==================================================================== */
     335                 : /*      Write the output image.                                         */
     336                 : /* ==================================================================== */
     337                 :     VSILFILE  *fpPBM;
     338                 : 
     339               3 :     fpPBM = VSIFOpenL( pszFilename, "wb+" );
     340               3 :     if( fpPBM == NULL )
     341                 :     {
     342                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     343                 :                   "Unable to create file `%s'.", 
     344               2 :                   pszFilename );
     345                 : 
     346               2 :         return NULL;
     347                 :     }
     348                 : 
     349                 : /* -------------------------------------------------------------------- */
     350                 : /*      Write the header lines.                                         */
     351                 : /* -------------------------------------------------------------------- */
     352               1 :     VSIFPrintfL( fpPBM, "/* XPM */\n" );
     353                 :     VSIFPrintfL( fpPBM, "static char *%s[] = {\n", 
     354               1 :              CPLGetBasename( pszFilename ) );
     355               1 :     VSIFPrintfL( fpPBM, "/* width height num_colors chars_per_pixel */\n" );
     356                 :     VSIFPrintfL( fpPBM, "\"  %3d   %3d     %3d             1\",\n",
     357               1 :              nXSize, nYSize, nActiveColors );
     358               1 :     VSIFPrintfL( fpPBM, "/* colors */\n" );
     359                 : 
     360                 : /* -------------------------------------------------------------------- */
     361                 : /*      Write the color table.                                          */
     362                 : /* -------------------------------------------------------------------- */
     363              88 :     for( i = 0; i < nActiveColors; i++ )
     364                 :     {
     365              87 :         if( asPixelColor[i].c4 < 128 )
     366               0 :             VSIFPrintfL( fpPBM, "\"%c c None\",\n", pszColorCodes[i] );
     367                 :         else
     368                 :             VSIFPrintfL( fpPBM, 
     369                 :                      "\"%c c #%02x%02x%02x\",\n",
     370              87 :                      pszColorCodes[i],
     371                 :                      asPixelColor[i].c1, 
     372                 :                      asPixelColor[i].c2, 
     373             174 :                      asPixelColor[i].c3 );
     374                 :     }
     375                 : 
     376                 : /* -------------------------------------------------------------------- */
     377                 : /*  Dump image.             */
     378                 : /* -------------------------------------------------------------------- */
     379                 :     int iLine;
     380                 :     GByte   *pabyScanline;
     381                 : 
     382               1 :     pabyScanline = (GByte *) CPLMalloc( nXSize );
     383              11 :     for( iLine = 0; iLine < nYSize; iLine++ )
     384                 :     {
     385                 :         poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
     386              10 :                           (void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0 );
     387                 :         
     388              10 :         VSIFPutcL( '"', fpPBM );
     389             110 :         for( int iPixel = 0; iPixel < nXSize; iPixel++ )
     390             100 :             VSIFPutcL( pszColorCodes[anPixelMapping[pabyScanline[iPixel]]], 
     391             100 :                    fpPBM);
     392              10 :         VSIFPrintfL( fpPBM, "\",\n" );
     393                 :     }
     394                 :     
     395               1 :     CPLFree( pabyScanline );
     396                 : 
     397                 : /* -------------------------------------------------------------------- */
     398                 : /*      cleanup                                                         */
     399                 : /* -------------------------------------------------------------------- */
     400               1 :     VSIFPrintfL( fpPBM, "};\n" );
     401               1 :     VSIFCloseL( fpPBM );
     402                 : 
     403                 : /* -------------------------------------------------------------------- */
     404                 : /*      Re-open dataset, and copy any auxilary pam information.         */
     405                 : /* -------------------------------------------------------------------- */
     406                 :     GDALPamDataset *poDS = (GDALPamDataset *) 
     407               1 :         GDALOpen( pszFilename, GA_ReadOnly );
     408                 : 
     409               1 :     if( poDS )
     410               1 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
     411                 : 
     412               1 :     return poDS;
     413                 : }
     414                 : 
     415                 : /************************************************************************/
     416                 : /*                          GDALRegister_XPM()                          */
     417                 : /************************************************************************/
     418                 : 
     419             582 : void GDALRegister_XPM()
     420                 : 
     421                 : {
     422                 :     GDALDriver  *poDriver;
     423                 : 
     424             582 :     if( GDALGetDriverByName( "XPM" ) == NULL )
     425                 :     {
     426             561 :         poDriver = new GDALDriver();
     427                 :         
     428             561 :         poDriver->SetDescription( "XPM" );
     429                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     430             561 :                                    "X11 PixMap Format" );
     431                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     432             561 :                                    "frmt_various.html#XPM" );
     433             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xpm" );
     434             561 :         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/x-xpixmap" );
     435                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
     436             561 :                                    "Byte" );
     437             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     438                 : 
     439             561 :         poDriver->pfnOpen = XPMDataset::Open;
     440             561 :         poDriver->pfnCreateCopy = XPMCreateCopy;
     441                 : 
     442             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     443                 :     }
     444             582 : }
     445                 : 
     446                 : /************************************************************************/
     447                 : /*                              ParseXPM()                              */
     448                 : /************************************************************************/
     449                 : 
     450                 : static unsigned char *
     451               2 : ParseXPM( const char *pszInput, int *pnXSize, int *pnYSize, 
     452                 :           GDALColorTable **ppoRetTable )
     453                 : 
     454                 : {
     455                 : /* ==================================================================== */
     456                 : /*      Parse input into an array of strings from within the first C    */
     457                 : /*      initializer (list os comma separated strings in braces).        */
     458                 : /* ==================================================================== */
     459               2 :     char **papszXPMList = NULL;
     460               2 :     const char *pszNext = pszInput;
     461                 :     int  i;
     462                 : 
     463                 :     // Skip till after open brace.
     464              66 :     while( *pszNext != '\0' && *pszNext != '{' ) 
     465              62 :         pszNext++;
     466                 : 
     467               2 :     if( *pszNext == '\0' )
     468               0 :         return NULL;
     469                 : 
     470               2 :     pszNext++;
     471                 : 
     472                 :     // Read lines till close brace.
     473                 :     
     474            2116 :     while( *pszNext != '\0' && *pszNext != '}' )
     475                 :     {
     476                 :         // skip whole comment. 
     477            2112 :         if( EQUALN(pszNext,"/*",2) )
     478                 :         {
     479               4 :             pszNext += 2;
     480             106 :             while( *pszNext != '\0' && !EQUALN(pszNext,"*/",2) )
     481              98 :                 pszNext++;
     482                 :         }
     483                 : 
     484                 :         // reading string constants
     485            2108 :         else if( *pszNext == '"' )
     486                 :         {
     487                 :             char   *pszLine;
     488                 : 
     489             698 :             pszNext++;
     490             698 :             i = 0;
     491                 : 
     492          265620 :             while( pszNext[i] != '\0' && pszNext[i] != '"' )
     493          264224 :                 i++;
     494                 : 
     495             698 :             if( pszNext[i] == '\0' )
     496                 :             {
     497               0 :                 CSLDestroy( papszXPMList );
     498               0 :                 return NULL;
     499                 :             }
     500                 : 
     501             698 :             pszLine = (char *) CPLMalloc(i+1);
     502             698 :             strncpy( pszLine, pszNext, i );
     503             698 :             pszLine[i] = '\0';
     504                 : 
     505             698 :             papszXPMList = CSLAddString( papszXPMList, pszLine );
     506             698 :             CPLFree( pszLine );
     507             698 :             pszNext = pszNext + i + 1;
     508                 :         }
     509                 : 
     510                 :         // just ignore everything else (whitespace, commas, newlines, etc).
     511                 :         else
     512            1410 :             pszNext++;
     513                 :     }
     514                 : 
     515               2 :     if( CSLCount(papszXPMList) < 3 || *pszNext != '}' )
     516                 :     {
     517               0 :         CSLDestroy( papszXPMList );
     518               0 :         return NULL;
     519                 :     }
     520                 :     
     521                 : /* -------------------------------------------------------------------- */
     522                 : /*      Get the image information.                                      */
     523                 : /* -------------------------------------------------------------------- */
     524                 :     int nColorCount, nCharsPerPixel;
     525                 : 
     526               2 :     if( sscanf( papszXPMList[0], "%d %d %d %d", 
     527                 :                 pnXSize, pnYSize, &nColorCount, &nCharsPerPixel ) != 4 )
     528                 :     {
     529                 :         CPLError( CE_Failure, CPLE_AppDefined,
     530                 :                   "Image definition (%s) not well formed.",
     531               0 :                   papszXPMList[0] );
     532               0 :         CSLDestroy( papszXPMList );
     533               0 :         return NULL;
     534                 :     }
     535                 : 
     536               2 :     if( nCharsPerPixel != 1 )
     537                 :     {
     538                 :         CPLError( CE_Failure, CPLE_AppDefined,
     539               0 :                   "Only one character per pixel XPM images supported by GDAL at this time." );
     540               0 :         CSLDestroy( papszXPMList );
     541               0 :         return NULL;
     542                 :     }
     543                 : 
     544                 : /* -------------------------------------------------------------------- */
     545                 : /*      Parse out colors.                                               */
     546                 : /* -------------------------------------------------------------------- */
     547                 :     int iColor;
     548                 :     int anCharLookup[256];
     549               2 :     GDALColorTable oCTable;
     550                 : 
     551             514 :     for( i = 0; i < 256; i++ ) 
     552             512 :         anCharLookup[i] = -1;
     553                 : 
     554             176 :     for( iColor = 0; iColor < nColorCount; iColor++ )
     555                 :     {
     556             174 :         char **papszTokens = CSLTokenizeString( papszXPMList[iColor+1]+1 );
     557                 :         GDALColorEntry sColor;
     558                 :         int            nRed, nGreen, nBlue;
     559                 : 
     560             174 :         if( CSLCount(papszTokens) != 2 || !EQUAL(papszTokens[0],"c") )
     561                 :         {
     562                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     563                 :                       "Ill formed color definition (%s) in XPM header.", 
     564               0 :                       papszXPMList[iColor+1] );
     565               0 :             CSLDestroy( papszXPMList );
     566               0 :             CSLDestroy( papszTokens );
     567               0 :             return NULL;
     568                 :         }
     569                 : 
     570             174 :         anCharLookup[(int)papszXPMList[iColor+1][0]] = iColor;
     571                 :         
     572             174 :         if( EQUAL(papszTokens[1],"None") )
     573                 :         {
     574               0 :             sColor.c1 = 0;
     575               0 :             sColor.c2 = 0;
     576               0 :             sColor.c3 = 0;
     577               0 :             sColor.c4 = 0;
     578                 :         }
     579             174 :         else if( sscanf( papszTokens[1], "#%02x%02x%02x", 
     580                 :                          &nRed, &nGreen, &nBlue ) != 3 )
     581                 :         {
     582                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     583                 :                       "Ill formed color definition (%s) in XPM header.", 
     584               0 :                       papszXPMList[iColor+1] );
     585               0 :             CSLDestroy( papszXPMList );
     586               0 :             CSLDestroy( papszTokens );
     587               0 :             return NULL;
     588                 :         }
     589                 :         else
     590                 :         {
     591             174 :             sColor.c1 = (short) nRed;
     592             174 :             sColor.c2 = (short) nGreen;
     593             174 :             sColor.c3 = (short) nBlue;
     594             174 :             sColor.c4 = 255;
     595                 :         }
     596                 : 
     597             174 :         oCTable.SetColorEntry( iColor, &sColor );
     598                 : 
     599             174 :         CSLDestroy( papszTokens );
     600                 :     }
     601                 : 
     602                 : /* -------------------------------------------------------------------- */
     603                 : /*      Prepare image buffer.                                           */
     604                 : /* -------------------------------------------------------------------- */
     605                 :     GByte *pabyImage;
     606                 : 
     607               2 :     pabyImage = (GByte *) VSIMalloc2(*pnXSize, *pnYSize);
     608               2 :     if( pabyImage == NULL )
     609                 :     {
     610                 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
     611                 :                   "Insufficient memory for %dx%d XPM image buffer.", 
     612               0 :                   *pnXSize, *pnYSize );
     613               0 :         CSLDestroy( papszXPMList );
     614               0 :         return NULL;
     615                 :     }
     616                 : 
     617               2 :     memset( pabyImage, 0, *pnXSize * *pnYSize );
     618                 : 
     619                 : /* -------------------------------------------------------------------- */
     620                 : /*      Parse image.                                                    */
     621                 : /* -------------------------------------------------------------------- */
     622             524 :     for( int iLine = 0; iLine < *pnYSize; iLine++ )
     623                 :     {
     624             522 :         const char *pszInLine = papszXPMList[iLine + nColorCount + 1];
     625                 : 
     626             522 :         if( pszInLine == NULL )
     627                 :         {
     628               0 :             CPLFree( pabyImage );
     629               0 :             CSLDestroy( papszXPMList );
     630                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     631               0 :                       "Insufficient imagery lines in XPM image." );
     632               0 :             return NULL;
     633                 :         }
     634                 : 
     635          525532 :         for( int iPixel = 0; 
     636          262766 :              pszInLine[iPixel] != '\0' && iPixel < *pnXSize; 
     637                 :              iPixel++ )
     638                 :         {
     639          262244 :             int nPixelValue = anCharLookup[(int)pszInLine[iPixel]];
     640          262244 :             if( nPixelValue != -1 )
     641          262244 :                 pabyImage[iLine * *pnXSize + iPixel] = (GByte) nPixelValue;
     642                 :         }
     643                 :     }
     644                 : 
     645               2 :     CSLDestroy( papszXPMList );
     646                 : 
     647               2 :     *ppoRetTable = oCTable.Clone();
     648                 : 
     649               2 :     return pabyImage;
     650                 : }

Generated by: LCOV version 1.7