LCOV - code coverage report
Current view: top level - frmts/gxf - gxfopen.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 210 382 55.0 %
Date: 2024-05-02 22:57:13 Functions: 8 13 61.5 %

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

Generated by: LCOV version 1.14