LCOV - code coverage report
Current view: directory - frmts/gxf - gxfopen.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 342 218 63.7 %
Date: 2012-12-26 Functions: 13 8 61.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: gxfopen.c 25164 2012-10-20 13:42:32Z rouault $
       3                 :  *
       4                 :  * Project:  GXF Reader
       5                 :  * Purpose:  Majority of Geosoft GXF reading code.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1998, Global Geomatics
      10                 :  * Copyright (c) 1998, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include <ctype.h>
      32                 : #include "gxfopen.h"
      33                 : 
      34                 : CPL_CVSID("$Id: gxfopen.c 25164 2012-10-20 13:42:32Z rouault $");
      35                 : 
      36                 : 
      37                 : /* this is also defined in gdal.h which we avoid in this separable component */
      38                 : #define CPLE_WrongFormat  200
      39                 : 
      40                 : #define MAX_LINE_COUNT_PER_HEADER       1000
      41                 : #define MAX_HEADER_COUNT                1000
      42                 : 
      43                 : /************************************************************************/
      44                 : /*                         GXFReadHeaderValue()                         */
      45                 : /*                                                                      */
      46                 : /*      Read one entry from the file header, and return it and it's     */
      47                 : /*      value in clean form.                                            */
      48                 : /************************************************************************/
      49                 : 
      50             109 : static char **GXFReadHeaderValue( FILE * fp, char * pszHTitle )
      51                 : 
      52                 : {
      53                 :     const char  *pszLine;
      54             109 :     char  **papszReturn = NULL;
      55                 :     int   i;
      56             109 :     int     nLineCount = 0, nReturnLineCount = 0;
      57             109 :     int     bContinuedLine = FALSE;
      58                 :     
      59                 : /* -------------------------------------------------------------------- */
      60                 : /*      Try to read a line.  If we fail or if this isn't a proper       */
      61                 : /*      header value then return the failure.                           */
      62                 : /* -------------------------------------------------------------------- */
      63             109 :     pszLine = CPLReadLine( fp );
      64             109 :     if( pszLine == NULL )
      65                 :     {
      66               0 :         strcpy( pszHTitle, "#EOF" );
      67               0 :         return( NULL );
      68                 :     }
      69                 : 
      70                 : /* -------------------------------------------------------------------- */
      71                 : /*      Extract the title.  It should be terminated by some sort of     */
      72                 : /*      white space.                                                    */
      73                 : /* -------------------------------------------------------------------- */
      74             109 :     for( i = 0; !isspace((unsigned char)pszLine[i]) && pszLine[i] != '\0' && i < 70; i++ ) {}
      75                 : 
      76             109 :     strncpy( pszHTitle, pszLine, i );
      77             109 :     pszHTitle[i] = '\0';
      78                 : 
      79                 : /* -------------------------------------------------------------------- */
      80                 : /*      If this is #GRID, then return ... we are at the end of the      */
      81                 : /*      header.                                                         */
      82                 : /* -------------------------------------------------------------------- */
      83             109 :     if( EQUAL(pszHTitle,"#GRID") )
      84               8 :         return NULL;
      85                 : 
      86                 : /* -------------------------------------------------------------------- */
      87                 : /*      Skip white space.                                               */
      88                 : /* -------------------------------------------------------------------- */
      89            5457 :     while( isspace((unsigned char)pszLine[i]) )
      90            5255 :         i++;
      91                 : 
      92                 : /* -------------------------------------------------------------------- */
      93                 : /*    If we have reached the end of the line, try to read another line. */
      94                 : /* -------------------------------------------------------------------- */
      95             101 :     if( pszLine[i] == '\0' )
      96                 :     {
      97             101 :         pszLine = CPLReadLine( fp );
      98             101 :         if( pszLine == NULL )
      99                 :         {
     100               0 :             strcpy( pszHTitle, "#EOF" );
     101               0 :             return( NULL );
     102                 :         }
     103             101 :         i = 0;
     104                 :     }
     105                 : 
     106                 : /* -------------------------------------------------------------------- */
     107                 : /*      Keeping adding the value stuff as new lines till we reach a     */
     108                 : /*      `#' mark at the beginning of a new line.                        */
     109                 : /* -------------------------------------------------------------------- */
     110                 :     do {
     111                 :         int   nNextChar;
     112                 :         char    *pszTrimmedLine;
     113                 : 
     114                 :         /* Lines are supposed to be limited to 80 characters */
     115             132 :         if( strlen(pszLine) > 1024 )
     116                 :         {
     117               0 :             CSLDestroy(papszReturn);
     118               0 :             return NULL;
     119                 :         }
     120                 :         
     121             132 :         pszTrimmedLine = CPLStrdup( pszLine );
     122                 : 
     123            7379 :         for( i = strlen(pszLine)-1; i >= 0 && pszLine[i] == ' '; i-- ) 
     124            7247 :             pszTrimmedLine[i] = '\0';
     125                 : 
     126             132 :         if( bContinuedLine )
     127                 :         {
     128               1 :             char* pszTmp = (char*) VSIMalloc((strlen(papszReturn[nReturnLineCount-1]) - 1) + strlen(pszTrimmedLine) + 1);
     129               1 :             if( pszTmp == NULL )
     130                 :             {
     131               0 :                 CSLDestroy(papszReturn);
     132               0 :                 return NULL;
     133                 :             }
     134               1 :             strcpy(pszTmp, papszReturn[nReturnLineCount-1]);
     135               1 :             strcpy(pszTmp + (strlen(papszReturn[nReturnLineCount-1]) - 1), pszTrimmedLine);
     136               1 :             CPLFree(papszReturn[nReturnLineCount-1]);
     137               1 :             papszReturn[nReturnLineCount-1] = pszTmp;
     138                 :         }
     139                 :         else
     140                 :         {
     141             131 :             papszReturn = CSLAddString( papszReturn, pszTrimmedLine );
     142             131 :             nReturnLineCount ++;
     143                 :         }
     144                 : 
     145                 :         /* Is it a continued line ? */
     146             132 :         bContinuedLine = ( i >= 0 && pszTrimmedLine[i] == '\\' );
     147                 :         
     148             132 :         CPLFree( pszTrimmedLine );
     149                 :         
     150             132 :         nNextChar = VSIFGetc( fp );
     151             132 :         VSIUngetc( nNextChar, fp );
     152                 :         
     153             132 :         if( nNextChar == '#' )
     154             101 :             pszLine = NULL;
     155                 :         else
     156                 :         {
     157              31 :             pszLine = CPLReadLine( fp );
     158              31 :             nLineCount ++;
     159                 :         }
     160             132 :     } while( pszLine != NULL && nLineCount < MAX_LINE_COUNT_PER_HEADER );
     161                 : 
     162             101 :     return( papszReturn );
     163                 : }
     164                 : 
     165                 : /************************************************************************/
     166                 : /*                              GXFOpen()                               */
     167                 : /************************************************************************/
     168                 : 
     169                 : /**
     170                 :  * Open a GXF file, and collect contents of the header.
     171                 :  *
     172                 :  * @param pszFilename the name of the file to open.
     173                 :  *
     174                 :  * @return a handle for use with other GXF functions to access the file.  This
     175                 :  * will be NULL if the access fails.
     176                 :  */
     177                 : 
     178               8 : GXFHandle GXFOpen( const char * pszFilename )
     179                 : 
     180                 : {
     181                 :     FILE  *fp;
     182                 :     GXFInfo_t *psGXF;
     183                 :     char  szTitle[71];
     184                 :     char  **papszList;
     185               8 :     int     nHeaderCount = 0;
     186                 : 
     187                 : /* -------------------------------------------------------------------- */
     188                 : /*      We open in binary to ensure that we can efficiently seek()      */
     189                 : /*      to any location when reading scanlines randomly.  If we         */
     190                 : /*      opened as text we might still be able to seek(), but I          */
     191                 : /*      believe that on Windows, the C library has to read through      */
     192                 : /*      all the data to find the right spot taking into account DOS     */
     193                 : /*      CRs.                                                            */
     194                 : /* -------------------------------------------------------------------- */
     195               8 :     fp = VSIFOpen( pszFilename, "rb" );
     196                 : 
     197               8 :     if( fp == NULL )
     198                 :     {
     199                 :         /* how to effectively communicate this error out? */
     200               0 :         CPLError( CE_Failure, CPLE_OpenFailed,
     201                 :                   "Unable to open file: %s\n", pszFilename );
     202               0 :         return NULL;
     203                 :     }
     204                 : 
     205                 : /* -------------------------------------------------------------------- */
     206                 : /*      Create the GXF Information object.                              */
     207                 : /* -------------------------------------------------------------------- */
     208               8 :     psGXF = (GXFInfo_t *) VSICalloc( sizeof(GXFInfo_t), 1 );
     209               8 :     psGXF->fp = fp;
     210               8 :     psGXF->dfTransformScale = 1.0;
     211               8 :     psGXF->nSense = GXFS_LL_RIGHT;
     212               8 :     psGXF->dfXPixelSize = 1.0;
     213               8 :     psGXF->dfYPixelSize = 1.0;
     214               8 :     psGXF->dfSetDummyTo = -1e12;
     215                 : 
     216               8 :     psGXF->dfUnitToMeter = 1.0;
     217               8 :     psGXF->pszTitle = VSIStrdup("");
     218                 :     
     219                 : /* -------------------------------------------------------------------- */
     220                 : /*      Read the header, one line at a time.                            */
     221                 : /* -------------------------------------------------------------------- */
     222             117 :     while( (papszList = GXFReadHeaderValue( fp, szTitle)) != NULL && nHeaderCount < MAX_HEADER_COUNT )
     223                 :     {
     224             101 :         if( EQUALN(szTitle,"#TITL",5) )
     225                 :         {
     226               6 :             CPLFree( psGXF->pszTitle );
     227               6 :             psGXF->pszTitle = CPLStrdup( papszList[0] );
     228                 :         }
     229              95 :         else if( EQUALN(szTitle,"#POIN",5) )
     230                 :         {
     231               8 :             psGXF->nRawXSize = atoi(papszList[0]);
     232                 :         }
     233              87 :         else if( EQUALN(szTitle,"#ROWS",5) )
     234                 :         {
     235               8 :             psGXF->nRawYSize = atoi(papszList[0]);
     236                 :         }
     237              79 :         else if( EQUALN(szTitle,"#PTSE",5) )
     238                 :         {
     239               7 :             psGXF->dfXPixelSize = CPLAtof(papszList[0]);
     240                 :         }
     241              72 :         else if( EQUALN(szTitle,"#RWSE",5) )
     242                 :         {
     243               7 :             psGXF->dfYPixelSize = CPLAtof(papszList[0]);
     244                 :         }
     245              65 :         else if( EQUALN(szTitle,"#DUMM",5) )
     246                 :         {
     247               2 :             memset( psGXF->szDummy, 0, sizeof(psGXF->szDummy));
     248               2 :             strncpy( psGXF->szDummy, papszList[0], sizeof(psGXF->szDummy) - 1);
     249               2 :             psGXF->dfSetDummyTo = CPLAtof(papszList[0]);
     250                 :         }
     251              63 :         else if( EQUALN(szTitle,"#XORI",5) )
     252                 :         {
     253               7 :             psGXF->dfXOrigin = CPLAtof(papszList[0]);
     254                 :         }
     255              56 :         else if( EQUALN(szTitle,"#YORI",5) )
     256                 :         {
     257               7 :             psGXF->dfYOrigin = CPLAtof(papszList[0]);
     258                 :         }
     259              49 :         else if( EQUALN(szTitle,"#ZMIN",5) )
     260                 :         {
     261               6 :             psGXF->dfZMinimum = CPLAtof(papszList[0]);
     262                 :         }
     263              43 :         else if( EQUALN(szTitle,"#ZMAX",5) )
     264                 :         {
     265               6 :             psGXF->dfZMaximum = CPLAtof(papszList[0]);
     266                 :         }
     267              37 :         else if( EQUALN(szTitle,"#SENS",5) )
     268                 :         {
     269               6 :             psGXF->nSense = atoi(papszList[0]);
     270                 :         }
     271              31 :         else if( EQUALN(szTitle,"#MAP_PROJECTION",8) )
     272                 :         {
     273               6 :             psGXF->papszMapProjection = papszList;
     274               6 :             papszList = NULL;
     275                 :         }
     276              25 :         else if( EQUALN(szTitle,"#MAP_D",5) )
     277                 :         {
     278               1 :             psGXF->papszMapDatumTransform = papszList;
     279               1 :             papszList = NULL;
     280                 :         }
     281              24 :         else if( EQUALN(szTitle,"#UNIT",5) )
     282                 :         {
     283                 :             char  **papszFields;
     284                 : 
     285               6 :             papszFields = CSLTokenizeStringComplex( papszList[0], ", ",
     286                 :                                                     TRUE, TRUE );
     287                 : 
     288               6 :             if( CSLCount(papszFields) > 1 )
     289                 :             {
     290               6 :                 psGXF->pszUnitName = VSIStrdup( papszFields[0] );
     291               6 :                 psGXF->dfUnitToMeter = CPLAtof( papszFields[1] );
     292               6 :                 if( psGXF->dfUnitToMeter == 0.0 )
     293               0 :                     psGXF->dfUnitToMeter = 1.0;
     294                 :             }
     295                 : 
     296               6 :             CSLDestroy( papszFields );
     297                 :         }
     298              18 :         else if( EQUALN(szTitle,"#TRAN",5) )
     299                 :         {
     300                 :             char  **papszFields;
     301                 : 
     302               6 :             papszFields = CSLTokenizeStringComplex( papszList[0], ", ",
     303                 :                                                     TRUE, TRUE );
     304                 : 
     305               6 :             if( CSLCount(papszFields) > 1 )
     306                 :             {
     307               6 :                 psGXF->dfTransformScale = CPLAtof(papszFields[0]);
     308               6 :                 psGXF->dfTransformOffset = CPLAtof(papszFields[1]);
     309                 :             }
     310                 : 
     311               6 :             if( CSLCount(papszFields) > 2 )
     312               0 :                 psGXF->pszTransformName = CPLStrdup( papszFields[2] );
     313                 : 
     314               6 :             CSLDestroy( papszFields );
     315                 :         }
     316              12 :         else if( EQUALN(szTitle,"#GTYPE",5) )
     317                 :         {
     318               5 :             psGXF->nGType = atoi(papszList[0]);
     319                 :         }
     320                 : 
     321             101 :         CSLDestroy( papszList );
     322             101 :         nHeaderCount ++;
     323                 :     }
     324                 : 
     325                 : /* -------------------------------------------------------------------- */
     326                 : /*      Did we find the #GRID?                                          */
     327                 : /* -------------------------------------------------------------------- */
     328               8 :     if( !EQUALN(szTitle,"#GRID",5) )
     329                 :     {
     330               0 :         GXFClose( psGXF );
     331               0 :         CPLError( CE_Failure, CPLE_WrongFormat,
     332                 :                   "Didn't parse through to #GRID successfully in.\n"
     333                 :                   "file `%s'.\n",
     334                 :                   pszFilename );
     335                 :         
     336               0 :         return NULL;
     337                 :     }
     338                 : 
     339                 : /* -------------------------------------------------------------------- */
     340                 : /*      Allocate, and initialize the raw scanline offset array.         */
     341                 : /* -------------------------------------------------------------------- */
     342               8 :     if( psGXF->nRawYSize <= 0 )
     343                 :     {
     344               0 :         GXFClose( psGXF );
     345               0 :         return NULL;
     346                 :     }
     347                 : 
     348               8 :     psGXF->panRawLineOffset = (long *)
     349               8 :         VSICalloc( sizeof(long), psGXF->nRawYSize+1 );
     350               8 :     if( psGXF->panRawLineOffset == NULL )
     351                 :     {
     352               0 :         GXFClose( psGXF );
     353               0 :         return NULL;
     354                 :     }
     355                 : 
     356               8 :     psGXF->panRawLineOffset[0] = VSIFTell( psGXF->fp );
     357                 : 
     358                 : /* -------------------------------------------------------------------- */
     359                 : /*      Update the zmin/zmax values to take into account #TRANSFORM     */
     360                 : /*      information.                                                    */
     361                 : /* -------------------------------------------------------------------- */
     362               8 :     if( psGXF->dfZMinimum != 0.0 || psGXF->dfZMaximum != 0.0 )
     363                 :     {
     364               6 :         psGXF->dfZMinimum = (psGXF->dfZMinimum * psGXF->dfTransformScale)
     365                 :                   + psGXF->dfTransformOffset;
     366               6 :         psGXF->dfZMaximum = (psGXF->dfZMaximum * psGXF->dfTransformScale)
     367                 :                   + psGXF->dfTransformOffset;
     368                 :     }
     369                 :     
     370               8 :     return( (GXFHandle) psGXF );
     371                 : }
     372                 : 
     373                 : /************************************************************************/
     374                 : /*                              GXFClose()                              */
     375                 : /************************************************************************/
     376                 : 
     377                 : /**
     378                 :  * Close GXF file opened with GXFOpen().
     379                 :  *
     380                 :  * @param hGXF handle to GXF file.
     381                 :  */
     382                 : 
     383               8 : void GXFClose( GXFHandle hGXF )
     384                 : 
     385                 : {
     386               8 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     387                 : 
     388               8 :     CPLFree( psGXF->panRawLineOffset );
     389               8 :     CPLFree( psGXF->pszUnitName );
     390               8 :     CSLDestroy( psGXF->papszMapDatumTransform );
     391               8 :     CSLDestroy( psGXF->papszMapProjection );
     392               8 :     CPLFree( psGXF->pszTitle );
     393               8 :     CPLFree( psGXF->pszTransformName );
     394                 : 
     395               8 :     VSIFClose( psGXF->fp );
     396                 : 
     397               8 :     CPLReadLine( NULL );
     398                 : 
     399               8 :     CPLFree( psGXF );
     400               8 : }
     401                 : 
     402                 : /************************************************************************/
     403                 : /*                           GXFParseBase90()                           */
     404                 : /*                                                                      */
     405                 : /*      Parse a base 90 number ... exceptions (repeat, and dummy)       */
     406                 : /*      values have to be recognised outside this function.             */
     407                 : /************************************************************************/
     408                 : 
     409          880328 : double GXFParseBase90( GXFInfo_t * psGXF, const char * pszText,
     410                 :                        int bScale )
     411                 : 
     412                 : {
     413          880328 :     int   i = 0, nValue = 0;
     414                 : 
     415         5281914 :     while( i < psGXF->nGType )
     416                 :     {
     417         3521258 :         nValue = nValue*90 + (pszText[i] - 37);
     418         3521258 :         i++;
     419                 :     }
     420                 : 
     421          880328 :     if( bScale ) 
     422          878297 :         return( (nValue * psGXF->dfTransformScale) + psGXF->dfTransformOffset);
     423                 :     else
     424            2031 :         return( nValue );
     425                 : }
     426                 : 
     427                 : 
     428                 : /************************************************************************/
     429                 : /*                       GXFReadRawScanlineFrom()                       */
     430                 : /************************************************************************/
     431                 : 
     432            2831 : static int GXFReadRawScanlineFrom( GXFInfo_t * psGXF, long iOffset,
     433                 :                                    long * pnNewOffset, double * padfLineBuf )
     434                 : 
     435                 : {
     436                 :     const char  *pszLine;
     437            2831 :     int   nValuesRead = 0, nValuesSought = psGXF->nRawXSize;
     438                 :     
     439            2831 :     VSIFSeek( psGXF->fp, iOffset, SEEK_SET );
     440                 : 
     441           78597 :     while( nValuesRead < nValuesSought )
     442                 :     {
     443           72935 :         pszLine = CPLReadLine( psGXF->fp );
     444           72935 :         if( pszLine == NULL )
     445               0 :             break;
     446                 : 
     447                 : /* -------------------------------------------------------------------- */
     448                 : /*      Uncompressed case.                                              */
     449                 : /* -------------------------------------------------------------------- */
     450           72935 :         if( psGXF->nGType == 0 )
     451                 :         {
     452                 :             /* we could just tokenize the line, but that's pretty expensive.
     453                 :                Instead I will parse on white space ``by hand''. */
     454          275709 :             while( *pszLine != '\0' && nValuesRead < nValuesSought )
     455                 :             {
     456                 :                 int   i;
     457                 :                 
     458                 :                 /* skip leading white space */
     459          219675 :                 for( ; isspace((unsigned char)*pszLine); pszLine++ ) {}
     460                 : 
     461                 :                 /* Skip the data value (non white space) */
     462          219675 :                 for( i = 0; pszLine[i] != '\0' && !isspace((unsigned char)pszLine[i]); i++) {}
     463                 : 
     464          219675 :                 if( strncmp(pszLine,psGXF->szDummy,i) == 0 )
     465                 :                 {
     466           34881 :                     padfLineBuf[nValuesRead++] = psGXF->dfSetDummyTo;
     467                 :                 }
     468                 :                 else
     469                 :                 {
     470          184794 :                     padfLineBuf[nValuesRead++] = CPLAtof(pszLine);
     471                 :                 }
     472                 : 
     473                 :                 /* skip further whitespace */
     474          219675 :                 for( pszLine += i; isspace((unsigned char)*pszLine); pszLine++ ) {}
     475                 :             }
     476                 :         }
     477                 : 
     478                 : /* -------------------------------------------------------------------- */
     479                 : /*      Compressed case.                                                */
     480                 : /* -------------------------------------------------------------------- */
     481                 :         else
     482                 :         {
     483           44918 :             int nLineLen = (int)strlen(pszLine);
     484                 : 
     485          971711 :             while( *pszLine != '\0' && nValuesRead < nValuesSought )
     486                 :             {
     487          881875 :                 if( nLineLen < psGXF->nGType )
     488               0 :                     return CE_Failure;
     489                 : 
     490          881875 :                 if( pszLine[0] == '!' )
     491                 :                 {
     492            2856 :                     padfLineBuf[nValuesRead++] = psGXF->dfSetDummyTo;
     493                 :                 }
     494          879019 :                 else if( pszLine[0] == '"' )
     495                 :                 {
     496                 :                     int   nCount, i;
     497                 :                     double  dfValue;
     498                 : 
     499            2031 :                     pszLine += psGXF->nGType;
     500            2031 :                     nLineLen -= psGXF->nGType;
     501            2031 :                     if( nLineLen < psGXF->nGType )
     502                 :                     {
     503              44 :                         pszLine = CPLReadLine( psGXF->fp );
     504              44 :                         if( pszLine == NULL )
     505               0 :                             return CE_Failure;
     506              44 :                         nLineLen = (int)strlen(pszLine);
     507              44 :                         if( nLineLen < psGXF->nGType )
     508               0 :                             return CE_Failure;
     509                 :                     }
     510                 :                     
     511            2031 :                     nCount = (int) GXFParseBase90( psGXF, pszLine, FALSE);
     512            2031 :                     pszLine += psGXF->nGType;
     513            2031 :                     nLineLen -= psGXF->nGType;
     514                 :                     
     515            2031 :                     if( nLineLen < psGXF->nGType )
     516                 :                     {
     517              68 :                         pszLine = CPLReadLine( psGXF->fp );
     518              68 :                         if( pszLine == NULL )
     519               0 :                             return CE_Failure;
     520              68 :                         nLineLen = (int)strlen(pszLine);
     521              68 :                         if( nLineLen < psGXF->nGType )
     522               0 :                             return CE_Failure;
     523                 :                     }
     524                 :                     
     525            2031 :                     if( *pszLine == '!' )
     526             722 :                         dfValue = psGXF->dfSetDummyTo;
     527                 :                     else
     528            1309 :                         dfValue = GXFParseBase90( psGXF, pszLine, TRUE );
     529                 : 
     530            2031 :                     if( nValuesRead + nCount > nValuesSought )
     531                 :                     {
     532               0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong count value");
     533               0 :                         return CE_Failure;
     534                 :                     }
     535                 :                     
     536           48184 :                     for( i=0; i < nCount && nValuesRead < nValuesSought; i++ )
     537           46153 :                         padfLineBuf[nValuesRead++] = dfValue;
     538                 :                 }
     539                 :                 else
     540                 :                 {
     541         1753976 :                     padfLineBuf[nValuesRead++] =
     542          876988 :                         GXFParseBase90( psGXF, pszLine, TRUE );
     543                 :                 }
     544                 : 
     545          881875 :                 pszLine += psGXF->nGType;
     546          881875 :                 nLineLen -= psGXF->nGType;
     547                 :             }
     548                 :         }
     549                 :     }
     550                 : 
     551                 : /* -------------------------------------------------------------------- */
     552                 : /*      Return the new offset, if requested.                            */
     553                 : /* -------------------------------------------------------------------- */
     554            2831 :     if( pnNewOffset != NULL )
     555                 :     {
     556            2831 :         *pnNewOffset = VSIFTell( psGXF->fp );
     557                 :     }
     558                 : 
     559            2831 :     return CE_None;
     560                 : }
     561                 : 
     562                 : /************************************************************************/
     563                 : /*                           GXFGetScanline()                           */
     564                 : /************************************************************************/
     565                 : 
     566                 : /**
     567                 :  * Read a scanline of raster data from GXF file.
     568                 :  *
     569                 :  * This function operates similarly to GXFGetRawScanline(), but it
     570                 :  * attempts to mirror data horizontally or vertically based on the #SENSE
     571                 :  * flag to return data in a top to bottom, and left to right organization.
     572                 :  * If the file is organized in columns (#SENSE is GXFS_UR_DOWN, GXFS_UL_DOWN,
     573                 :  * GXFS_LR_UP, or GXFS_LL_UP) then this function will fail, returning
     574                 :  * CE_Failure, and reporting a sense error.
     575                 :  *
     576                 :  * See GXFGetRawScanline() for other notes.
     577                 :  *
     578                 :  * @param hGXF the GXF file handle, as returned from GXFOpen().
     579                 :  * @param iScanline the scanline to read, zero is the top scanline.
     580                 :  * @param padfLineBuf a buffer of doubles into which the scanline pixel
     581                 :  * values are read.  This must be at least as long as a scanline.
     582                 :  *
     583                 :  * @return CE_None if access succeeds or CE_Failure if something goes wrong.
     584                 :  */
     585                 : 
     586            1538 : CPLErr GXFGetScanline( GXFHandle hGXF, int iScanline, double * padfLineBuf )
     587                 : 
     588                 : {
     589            1538 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     590                 :     CPLErr  nErr;
     591                 :     int   iRawScanline;
     592                 : 
     593            3076 :     if( psGXF->nSense == GXFS_LL_RIGHT
     594            1776 :         || psGXF->nSense == GXFS_LR_LEFT )
     595                 :     {
     596            1300 :         iRawScanline = psGXF->nRawYSize - iScanline - 1;
     597                 :     }
     598                 : 
     599             476 :     else if( psGXF->nSense == GXFS_UL_RIGHT
     600             238 :              || psGXF->nSense == GXFS_UR_LEFT )
     601                 :     {
     602             238 :         iRawScanline = iScanline;
     603                 :     }
     604                 :     else
     605                 :     {
     606               0 :         CPLError( CE_Failure, CPLE_AppDefined,
     607                 :                   "Unable to support vertically oriented images." );
     608               0 :         return( CE_Failure );
     609                 :     }
     610                 : 
     611            1538 :     nErr = GXFGetRawScanline( hGXF, iRawScanline, padfLineBuf );
     612                 : 
     613            4614 :     if( nErr == CE_None
     614            3076 :         && (psGXF->nSense == GXFS_LR_LEFT || psGXF->nSense == GXFS_UR_LEFT) )
     615                 :     {
     616                 :         int i;
     617                 :         double  dfTemp;
     618                 :         
     619               0 :         for( i = psGXF->nRawXSize / 2 - 1; i >= 0; i-- )
     620                 :         {
     621               0 :             dfTemp = padfLineBuf[i];
     622               0 :             padfLineBuf[i] = padfLineBuf[psGXF->nRawXSize-i-1];
     623               0 :             padfLineBuf[psGXF->nRawXSize-i-1] = dfTemp;
     624                 :         }
     625                 :     }
     626                 : 
     627            1538 :     return( nErr );
     628                 : }
     629                 : 
     630                 : /************************************************************************/
     631                 : /*                         GXFGetRawScanline()                          */
     632                 : /************************************************************************/
     633                 : 
     634                 : /**
     635                 :  * Read a scanline of raster data from GXF file.
     636                 :  *
     637                 :  * This function will read a row of data from the GXF file.  It is "Raw"
     638                 :  * in the sense that it doesn't attempt to account for the #SENSE flag as
     639                 :  * the GXFGetScanline() function does.  Unlike GXFGetScanline(), this function
     640                 :  * supports column organized files.
     641                 :  *
     642                 :  * Any dummy pixels are assigned the dummy value indicated by GXFGetRawInfo().
     643                 :  *
     644                 :  * @param hGXF the GXF file handle, as returned from GXFOpen().
     645                 :  * @param iScanline the scanline to read, zero is the first scanline in the
     646                 :  * file. 
     647                 :  * @param padfLineBuf a buffer of doubles into which the scanline pixel
     648                 :  * values are read.  This must be at least as long as a scanline.
     649                 :  *
     650                 :  * @return CE_None if access succeeds or CE_Failure if something goes wrong.
     651                 :  */
     652                 : 
     653            2831 : CPLErr GXFGetRawScanline( GXFHandle hGXF, int iScanline, double * padfLineBuf )
     654                 : 
     655                 : {
     656            2831 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     657                 :     CPLErr  nErr;
     658                 :     
     659                 : /* -------------------------------------------------------------------- */
     660                 : /*      Validate scanline.                                              */
     661                 : /* -------------------------------------------------------------------- */
     662            2831 :     if( iScanline < 0 || iScanline >= psGXF->nRawYSize )
     663                 :     {
     664               0 :         CPLError( CE_Failure, CPLE_IllegalArg,
     665                 :                   "GXFGetRawScanline(): Scanline `%d' does not exist.\n",
     666                 :                   iScanline );
     667               0 :         return CE_Failure;
     668                 :     }
     669                 : 
     670                 : /* -------------------------------------------------------------------- */
     671                 : /*      If we don't have the requested scanline, fetch preceeding       */
     672                 : /*      scanlines to find the pointer to this scanline.                 */
     673                 : /* -------------------------------------------------------------------- */
     674            2831 :     if( psGXF->panRawLineOffset[iScanline] == 0 )
     675                 :     {
     676                 :         int   i;
     677                 :         
     678               7 :         CPLAssert( iScanline > 0 );
     679                 : 
     680            1300 :         for( i = 0; i < iScanline; i++ )
     681                 :         {
     682            1293 :             if( psGXF->panRawLineOffset[i+1] == 0 )
     683                 :             {
     684            1293 :                 nErr = GXFGetRawScanline( hGXF, i, padfLineBuf );
     685            1293 :                 if( nErr != CE_None )
     686               0 :                     return( nErr );
     687                 :             }
     688                 :         }
     689                 :     }
     690                 : 
     691                 : /* -------------------------------------------------------------------- */
     692                 : /*      Get this scanline, and update the offset for the next line.     */
     693                 : /* -------------------------------------------------------------------- */
     694            5662 :     nErr = (CPLErr)
     695            2831 :         GXFReadRawScanlineFrom( psGXF, psGXF->panRawLineOffset[iScanline],
     696                 :                                 psGXF->panRawLineOffset+iScanline+1,
     697                 :                                 padfLineBuf );
     698                 : 
     699            2831 :     return nErr;
     700                 : }
     701                 : 
     702                 : /************************************************************************/
     703                 : /*                         GXFScanForZMinMax()                          */
     704                 : /*                                                                      */
     705                 : /*      The header doesn't contain the ZMin/ZMax values, but the        */
     706                 : /*      application has requested it ... scan the entire image for      */
     707                 : /*      it.                                                             */
     708                 : /************************************************************************/
     709                 : 
     710               0 : static void GXFScanForZMinMax( GXFHandle hGXF )
     711                 : 
     712                 : {
     713               0 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     714                 :     int   iLine, iPixel;
     715                 :     double  *padfScanline;
     716                 :     
     717                 : 
     718               0 :     padfScanline = (double *) VSICalloc(sizeof(double),psGXF->nRawXSize);
     719               0 :     if( padfScanline == NULL )
     720               0 :         return;
     721                 : 
     722               0 :     psGXF->dfZMinimum = 1e50;
     723               0 :     psGXF->dfZMaximum = -1e50;
     724                 : 
     725               0 :     for( iLine = 0; iLine < psGXF->nRawYSize; iLine++ )
     726                 :     {
     727               0 :         if( GXFGetRawScanline( hGXF, iLine, padfScanline ) != CE_None )
     728               0 :             break;
     729                 : 
     730               0 :         for( iPixel = 0; iPixel < psGXF->nRawXSize; iPixel++ )
     731                 :         {
     732               0 :             if( padfScanline[iPixel] != psGXF->dfSetDummyTo )
     733                 :             {
     734               0 :                 psGXF->dfZMinimum =
     735               0 :                     MIN(psGXF->dfZMinimum,padfScanline[iPixel]);
     736               0 :                 psGXF->dfZMaximum =
     737               0 :                     MAX(psGXF->dfZMaximum,padfScanline[iPixel]);
     738                 :             }
     739                 :         }
     740                 :     }
     741                 : 
     742               0 :     VSIFree( padfScanline );
     743                 : 
     744                 : /* -------------------------------------------------------------------- */
     745                 : /*      Did we get any real data points?                                */
     746                 : /* -------------------------------------------------------------------- */
     747               0 :     if( psGXF->dfZMinimum > psGXF->dfZMaximum )
     748                 :     {
     749               0 :         psGXF->dfZMinimum = 0.0;
     750               0 :         psGXF->dfZMaximum = 0.0;
     751                 :     }
     752                 : }
     753                 : 
     754                 : /************************************************************************/
     755                 : /*                             GXFGetRawInfo()                          */
     756                 : /************************************************************************/
     757                 : 
     758                 : /**
     759                 :  * Fetch header information about a GXF file.
     760                 :  *
     761                 :  * Note that the X and Y sizes are of the raw raster and don't take into
     762                 :  * account the #SENSE flag.  If the file is column oriented (rows in the
     763                 :  * files are actually columns in the raster) these values would need to be
     764                 :  * transposed for the actual raster.
     765                 :  *
     766                 :  * The legal pnSense values are:
     767                 :  * <ul>
     768                 :  * <li> GXFS_LL_UP(-1): lower left origin, scanning up.
     769                 :  * <li> GXFS_LL_RIGHT(1): lower left origin, scanning right.
     770                 :  * <li> GXFS_UL_RIGHT(-2): upper left origin, scanning right.
     771                 :  * <li> GXFS_UL_DOWN(2): upper left origin, scanning down.
     772                 :  * <li> GXFS_UR_DOWN(-3): upper right origin, scanning down.
     773                 :  * <li> GXFS_UR_LEFT(3): upper right origin, scanning left.
     774                 :  * <li> GXFS_LR_LEFT(-4): lower right origin, scanning left.
     775                 :  * <li> GXFS_LR_UP(4): lower right origin, scanning up.
     776                 :  * </ul>
     777                 :  *
     778                 :  * Note that the GXFGetScanline() function attempts to provide a GXFS_UL_RIGHT
     779                 :  * view onto files, but doesn't handle the *_DOWN and *_UP oriented files.
     780                 :  *
     781                 :  * The Z min and max values may not occur in the GXF header.  If they are
     782                 :  * requested, and aren't available in the header the entire file is scanned
     783                 :  * in order to establish them.  This can be expensive.
     784                 :  *
     785                 :  * If no #DUMMY value was specified in the file, a default of -1e12 is used.
     786                 :  * 
     787                 :  * @param hGXF handle to GXF file returned by GXFOpen().
     788                 :  * @param pnXSize int to be set with the width of the raw raster.  May be NULL.
     789                 :  * @param pnYSize int to be set with the height of the raw raster. May be NULL.
     790                 :  * @param pnSense int to set with #SENSE flag, may be NULL.
     791                 :  * @param pdfZMin double to set with minimum raster value, may be NULL.
     792                 :  * @param pdfZMax double to set with minimum raster value, may be NULL.
     793                 :  * @param pdfDummy double to set with dummy (nodata / invalid data) pixel
     794                 :  * value.
     795                 :  */ 
     796                 : 
     797               8 : CPLErr GXFGetRawInfo( GXFHandle hGXF, int *pnXSize, int *pnYSize,
     798                 :                       int * pnSense, double * pdfZMin, double * pdfZMax,
     799                 :                       double * pdfDummy )
     800                 : 
     801                 : {
     802               8 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     803                 : 
     804               8 :     if( pnXSize != NULL )
     805               8 :         *pnXSize = psGXF->nRawXSize;
     806                 : 
     807               8 :     if( pnYSize != NULL )
     808               8 :         *pnYSize = psGXF->nRawYSize;
     809                 : 
     810               8 :     if( pnSense != NULL )
     811               0 :         *pnSense = psGXF->nSense;
     812                 : 
     813               8 :     if( (pdfZMin != NULL || pdfZMax != NULL)
     814               0 :         && psGXF->dfZMinimum == 0.0 && psGXF->dfZMaximum == 0.0 )
     815                 :     {
     816               0 :         GXFScanForZMinMax( hGXF );
     817                 :     }
     818                 :     
     819               8 :     if( pdfZMin != NULL )
     820               0 :         *pdfZMin = psGXF->dfZMinimum;
     821                 : 
     822               8 :     if( pdfZMax != NULL )
     823               0 :         *pdfZMax = psGXF->dfZMaximum;
     824                 : 
     825               8 :     if( pdfDummy != NULL )
     826               8 :         *pdfDummy = psGXF->dfSetDummyTo;
     827                 : 
     828               8 :     return( CE_None );
     829                 : }
     830                 : 
     831                 : /************************************************************************/
     832                 : /*                        GXFGetMapProjection()                         */
     833                 : /************************************************************************/
     834                 : 
     835                 : /**
     836                 :  * Return the lines related to the map projection.  It is up to   
     837                 :  * the caller to parse them and interprete.  The return result    
     838                 :  * will be NULL if no #MAP_PROJECTION line was found in the header.
     839                 :  * 
     840                 :  * @param hGXF the GXF file handle.
     841                 :  *
     842                 :  * @return a NULL terminated array of string pointers containing the
     843                 :  * projection, or NULL.  The strings remained owned by the GXF API, and
     844                 :  * should not be modified or freed by the caller.  
     845                 :  */
     846                 : 
     847               0 : char **GXFGetMapProjection( GXFHandle hGXF )
     848                 : 
     849                 : {
     850               0 :     return( ((GXFInfo_t *) hGXF)->papszMapProjection );
     851                 : }
     852                 : 
     853                 : /************************************************************************/
     854                 : /*                      GXFGetMapDatumTransform()                       */
     855                 : /************************************************************************/
     856                 : 
     857                 : /**
     858                 :  * Return the lines related to the datum transformation.  It is up to   
     859                 :  * the caller to parse them and interpret.  The return result    
     860                 :  * will be NULL if no #MAP_DATUM_TRANSFORM line was found in the header.
     861                 :  * 
     862                 :  * @param hGXF the GXF file handle.
     863                 :  *
     864                 :  * @return a NULL terminated array of string pointers containing the
     865                 :  * datum, or NULL.  The strings remained owned by the GXF API, and
     866                 :  * should not be modified or freed by the caller.  
     867                 :  */
     868                 : 
     869               0 : char **GXFGetMapDatumTransform( GXFHandle hGXF )
     870                 : 
     871                 : {
     872               0 :     return( ((GXFInfo_t *) hGXF)->papszMapDatumTransform );
     873                 : }
     874                 : 
     875                 : /************************************************************************/
     876                 : /*                         GXFGetRawPosition()                          */
     877                 : /************************************************************************/
     878                 : 
     879                 : /**
     880                 :  * Get the raw grid positioning information.
     881                 :  *
     882                 :  * Note that these coordinates refer to the raw grid, and are in the units
     883                 :  * specified by the #UNITS field.  See GXFGetPosition() for a similar
     884                 :  * function that takes into account the #SENSE values similarly to
     885                 :  * GXFGetScanline().
     886                 :  *
     887                 :  * Note that the pixel values are considered to be point values in GXF,
     888                 :  * and thus the origin is for the first point.  If you consider the pixels
     889                 :  * to be areas, then the origin is for the center of the origin pixel, not
     890                 :  * the outer corner.
     891                 :  *
     892                 :  * @param hGXF the GXF file handle.
     893                 :  * @param pdfXOrigin X position of the origin in the base coordinate system.
     894                 :  * @param pdfYOrigin Y position of the origin in the base coordinate system.
     895                 :  * @param pdfXPixelSize X pixel size in base coordinates.
     896                 :  * @param pdfYPixelSize Y pixel size in base coordinates.
     897                 :  * @param pdfRotation rotation in degrees counter-clockwise from the
     898                 :  * base coordinate system.
     899                 :  *
     900                 :  * @return Returns CE_None if successful, or CE_Failure if no posiitioning
     901                 :  * information was found in the file.
     902                 :  */
     903                 :  
     904                 : 
     905               0 : CPLErr GXFGetRawPosition( GXFHandle hGXF,
     906                 :                           double * pdfXOrigin, double * pdfYOrigin,
     907                 :                           double * pdfXPixelSize, double * pdfYPixelSize,
     908                 :                           double * pdfRotation )
     909                 : 
     910                 : {
     911               0 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     912                 :     
     913               0 :     if( pdfXOrigin != NULL )
     914               0 :         *pdfXOrigin = psGXF->dfXOrigin;
     915               0 :     if( pdfYOrigin != NULL )
     916               0 :         *pdfYOrigin = psGXF->dfYOrigin;
     917               0 :     if( pdfXPixelSize != NULL )
     918               0 :         *pdfXPixelSize = psGXF->dfXPixelSize;
     919               0 :     if( pdfYPixelSize != NULL )
     920               0 :         *pdfYPixelSize = psGXF->dfYPixelSize;
     921               0 :     if( pdfRotation != NULL )
     922               0 :         *pdfRotation = psGXF->dfRotation;
     923                 : 
     924               0 :     if( psGXF->dfXOrigin == 0.0 && psGXF->dfYOrigin == 0.0
     925               0 :         && psGXF->dfXPixelSize == 0.0 && psGXF->dfYPixelSize == 0.0 )
     926               0 :         return( CE_Failure );
     927                 :     else
     928               0 :         return( CE_None );
     929                 : }
     930                 : 
     931                 : 
     932                 : /************************************************************************/
     933                 : /*                           GXFGetPosition()                           */
     934                 : /************************************************************************/
     935                 : 
     936                 : /**
     937                 :  * Get the grid positioning information.
     938                 :  *
     939                 :  * Note that these coordinates refer to the grid positioning after taking
     940                 :  * into account the #SENSE flag (as is done by the GXFGetScanline()) function.
     941                 :  *
     942                 :  * Note that the pixel values are considered to be point values in GXF,
     943                 :  * and thus the origin is for the first point.  If you consider the pixels
     944                 :  * to be areas, then the origin is for the center of the origin pixel, not
     945                 :  * the outer corner.
     946                 :  *
     947                 :  * This function does not support vertically oriented images, nor does it
     948                 :  * properly transform rotation for images with a SENSE other than
     949                 :  * GXFS_UL_RIGHT.
     950                 :  *
     951                 :  * @param hGXF the GXF file handle.
     952                 :  * @param pdfXOrigin X position of the origin in the base coordinate system.
     953                 :  * @param pdfYOrigin Y position of the origin in the base coordinate system.
     954                 :  * @param pdfXPixelSize X pixel size in base coordinates.
     955                 :  * @param pdfYPixelSize Y pixel size in base coordinates.
     956                 :  * @param pdfRotation rotation in degrees counter-clockwise from the
     957                 :  * base coordinate system.
     958                 :  *
     959                 :  * @return Returns CE_None if successful, or CE_Failure if no posiitioning
     960                 :  * information was found in the file.
     961                 :  */
     962                 :  
     963                 : 
     964               0 : CPLErr GXFGetPosition( GXFHandle hGXF,
     965                 :                        double * pdfXOrigin, double * pdfYOrigin,
     966                 :                        double * pdfXPixelSize, double * pdfYPixelSize,
     967                 :                        double * pdfRotation )
     968                 : 
     969                 : {
     970               0 :     GXFInfo_t *psGXF = (GXFInfo_t *) hGXF;
     971                 :     double  dfCXOrigin, dfCYOrigin, dfCXPixelSize, dfCYPixelSize;
     972                 : 
     973               0 :     switch( psGXF->nSense )
     974                 :     {
     975                 :       case GXFS_UL_RIGHT:
     976               0 :         dfCXOrigin = psGXF->dfXOrigin;
     977               0 :         dfCYOrigin = psGXF->dfYOrigin;
     978               0 :         dfCXPixelSize = psGXF->dfXPixelSize;
     979               0 :         dfCYPixelSize = psGXF->dfYPixelSize;
     980               0 :         break;
     981                 :         
     982                 :       case GXFS_UR_LEFT:
     983               0 :         dfCXOrigin = psGXF->dfXOrigin
     984               0 :                    - (psGXF->nRawXSize-1) * psGXF->dfXPixelSize;
     985               0 :         dfCYOrigin = psGXF->dfYOrigin;
     986               0 :         dfCXPixelSize = psGXF->dfXPixelSize;
     987               0 :         dfCYPixelSize = psGXF->dfYPixelSize;
     988               0 :         break;
     989                 :         
     990                 :       case GXFS_LL_RIGHT:
     991               0 :         dfCXOrigin = psGXF->dfXOrigin;
     992               0 :         dfCYOrigin = psGXF->dfYOrigin
     993               0 :                      + (psGXF->nRawYSize-1) * psGXF->dfYPixelSize;
     994               0 :         dfCXPixelSize = psGXF->dfXPixelSize;
     995               0 :         dfCYPixelSize = psGXF->dfYPixelSize;
     996               0 :         break;
     997                 :         
     998                 :       case GXFS_LR_LEFT:
     999               0 :         dfCXOrigin = psGXF->dfXOrigin
    1000               0 :                    - (psGXF->nRawXSize-1) * psGXF->dfXPixelSize;
    1001               0 :         dfCYOrigin = psGXF->dfYOrigin
    1002               0 :                      + (psGXF->nRawYSize-1) * psGXF->dfYPixelSize;
    1003               0 :         dfCXPixelSize = psGXF->dfXPixelSize;
    1004               0 :         dfCYPixelSize = psGXF->dfYPixelSize;
    1005               0 :         break;
    1006                 : 
    1007                 :       default:
    1008               0 :         CPLError( CE_Failure, CPLE_AppDefined,
    1009                 :            "GXFGetPosition() doesn't support vertically organized images." );
    1010               0 :         return CE_Failure;
    1011                 :     }
    1012                 : 
    1013               0 :     if( pdfXOrigin != NULL )
    1014               0 :         *pdfXOrigin = dfCXOrigin;
    1015               0 :     if( pdfYOrigin != NULL )
    1016               0 :         *pdfYOrigin = dfCYOrigin;
    1017               0 :     if( pdfXPixelSize != NULL )
    1018               0 :         *pdfXPixelSize = dfCXPixelSize;
    1019               0 :     if( pdfYPixelSize != NULL )
    1020               0 :         *pdfYPixelSize = dfCYPixelSize;
    1021               0 :     if( pdfRotation != NULL )
    1022               0 :         *pdfRotation = psGXF->dfRotation;
    1023                 : 
    1024               0 :     if( psGXF->dfXOrigin == 0.0 && psGXF->dfYOrigin == 0.0
    1025               0 :         && psGXF->dfXPixelSize == 0.0 && psGXF->dfYPixelSize == 0.0 )
    1026               0 :         return( CE_Failure );
    1027                 :     else
    1028               0 :         return( CE_None );
    1029                 : }
    1030                 : 
    1031                 : 

Generated by: LCOV version 1.7