LCOV - code coverage report
Current view: directory - frmts/xpm - xpmdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 221 177 80.1 %
Date: 2010-01-09 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.7