LCOV - code coverage report
Current view: top level - frmts/ceos - ceosopen.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 89 124 71.8 %
Date: 2024-04-29 01:40:10 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  CEOS Translator
       5             :  * Purpose:  Implementation of non-GDAL dependent CEOS support.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Frank Warmerdam
      10             :  * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
      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 "ceosopen.h"
      32             : 
      33           4 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      34             : {
      35           4 : }
      36             : 
      37             : /************************************************************************/
      38             : /*                            CEOSScanInt()                             */
      39             : /*                                                                      */
      40             : /*      Read up to nMaxChars from the passed string, and interpret      */
      41             : /*      as an integer.                                                  */
      42             : /************************************************************************/
      43             : 
      44          18 : static int CEOSScanInt(const char *pszString, int nMaxChars)
      45             : 
      46             : {
      47          18 :     char szWorking[33] = {0};
      48             :     int i;
      49             : 
      50          18 :     if (nMaxChars > 32 || nMaxChars == 0)
      51           0 :         nMaxChars = 32;
      52             : 
      53         114 :     for (i = 0; i < nMaxChars && pszString[i] != '\0'; i++)
      54          96 :         szWorking[i] = pszString[i];
      55             : 
      56          18 :     szWorking[i] = '\0';
      57             : 
      58          18 :     return (atoi(szWorking));
      59             : }
      60             : 
      61             : /************************************************************************/
      62             : /*                           CEOSReadRecord()                           */
      63             : /*                                                                      */
      64             : /*      Read a single CEOS record at the current point in the file.     */
      65             : /*      Return NULL after reporting an error if it fails, otherwise     */
      66             : /*      return the record.                                              */
      67             : /************************************************************************/
      68             : 
      69           4 : CEOSRecord *CEOSReadRecord(CEOSImage *psImage)
      70             : 
      71             : {
      72             :     GByte abyHeader[12];
      73             :     CEOSRecord *psRecord;
      74             :     GUInt32 nRecordNumUInt32, nLengthUInt32;
      75             : 
      76             :     /* -------------------------------------------------------------------- */
      77             :     /*      Read the standard CEOS header.                                  */
      78             :     /* -------------------------------------------------------------------- */
      79           4 :     if (VSIFEofL(psImage->fpImage))
      80           0 :         return NULL;
      81             : 
      82           4 :     if (VSIFReadL(abyHeader, 1, 12, psImage->fpImage) != 12)
      83             :     {
      84           0 :         CPLError(CE_Failure, CPLE_FileIO,
      85             :                  "Ran out of data reading CEOS record.");
      86           0 :         return NULL;
      87             :     }
      88             : 
      89             :     /* -------------------------------------------------------------------- */
      90             :     /*      Extract this information.                                       */
      91             :     /* -------------------------------------------------------------------- */
      92           4 :     psRecord = (CEOSRecord *)CPLMalloc(sizeof(CEOSRecord));
      93           4 :     if (psImage->bLittleEndian)
      94             :     {
      95           2 :         CPL_SWAP32PTR(abyHeader + 0);
      96           2 :         CPL_SWAP32PTR(abyHeader + 8);
      97             :     }
      98             : 
      99           4 :     nRecordNumUInt32 = ((unsigned)abyHeader[0] << 24) + (abyHeader[1] << 16) +
     100           4 :                        (abyHeader[2] << 8) + abyHeader[3];
     101             : 
     102           4 :     psRecord->nRecordType = ((unsigned)abyHeader[4] << 24) +
     103           4 :                             (abyHeader[5] << 16) + (abyHeader[6] << 8) +
     104           4 :                             abyHeader[7];
     105             : 
     106           4 :     nLengthUInt32 = ((unsigned)abyHeader[8] << 24) + (abyHeader[9] << 16) +
     107           4 :                     (abyHeader[10] << 8) + abyHeader[11];
     108             : 
     109             :     /* -------------------------------------------------------------------- */
     110             :     /*      Does it look reasonable?  We assume there can't be too many     */
     111             :     /*      records and that the length must be between 12 and 200000.      */
     112             :     /* -------------------------------------------------------------------- */
     113           4 :     if (nRecordNumUInt32 > 200000 || nLengthUInt32 < 12 ||
     114             :         nLengthUInt32 > 200000)
     115             :     {
     116           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     117             :                  "CEOS record leader appears to be corrupt.\n"
     118             :                  "Record Number = %u, Record Length = %u\n",
     119             :                  nRecordNumUInt32, nLengthUInt32);
     120           0 :         CPLFree(psRecord);
     121           0 :         return NULL;
     122             :     }
     123             : 
     124           4 :     psRecord->nRecordNum = (int)nRecordNumUInt32;
     125           4 :     psRecord->nLength = (int)nLengthUInt32;
     126             : 
     127             :     /* -------------------------------------------------------------------- */
     128             :     /*      Read the remainder of the record into a buffer.  Ensure that    */
     129             :     /*      the first 12 bytes gets moved into this buffer as well.         */
     130             :     /* -------------------------------------------------------------------- */
     131           4 :     psRecord->pachData = (char *)VSI_MALLOC_VERBOSE(psRecord->nLength);
     132           4 :     if (psRecord->pachData == NULL)
     133             :     {
     134           0 :         CPLFree(psRecord);
     135           0 :         return NULL;
     136             :     }
     137             : 
     138           4 :     memcpy(psRecord->pachData, abyHeader, 12);
     139             : 
     140           4 :     if ((int)VSIFReadL(psRecord->pachData + 12, 1, psRecord->nLength - 12,
     141           4 :                        psImage->fpImage) != psRecord->nLength - 12)
     142             :     {
     143           0 :         CPLError(CE_Failure, CPLE_FileIO, "Short read on CEOS record data.\n");
     144           0 :         CPLFree(psRecord->pachData);
     145           0 :         CPLFree(psRecord);
     146           0 :         return NULL;
     147             :     }
     148             : 
     149           4 :     return psRecord;
     150             : }
     151             : 
     152             : /************************************************************************/
     153             : /*                         CEOSDestroyRecord()                          */
     154             : /*                                                                      */
     155             : /*      Free a record.                                                  */
     156             : /************************************************************************/
     157             : 
     158           4 : void CEOSDestroyRecord(CEOSRecord *psRecord)
     159             : 
     160             : {
     161           4 :     if (psRecord)
     162             :     {
     163           4 :         CPLFree(psRecord->pachData);
     164           4 :         CPLFree(psRecord);
     165             :     }
     166           4 : }
     167             : 
     168             : /************************************************************************/
     169             : /*                              CEOSOpen()                              */
     170             : /************************************************************************/
     171             : 
     172             : /**
     173             :  * Open a CEOS transfer.
     174             :  *
     175             :  * @param pszFilename The name of the CEOS imagery file (i.e. imag_01.dat).
     176             :  * @param pszAccess An fopen() style access string.  Should be either "rb" for
     177             :  * read-only access, or "r+b" for read, and update access.
     178             :  *
     179             :  * @return A CEOSImage pointer as a handle to the image.  The CEOSImage also
     180             :  * has various information about the image available.  A NULL is returned
     181             :  * if an error occurs.
     182             :  */
     183             : 
     184           4 : CEOSImage *CEOSOpen(const char *pszFilename, const char *pszAccess)
     185             : 
     186             : {
     187             :     VSILFILE *fp;
     188             :     CEOSRecord *psRecord;
     189             :     CEOSImage *psImage;
     190             :     int nSeqNum, i;
     191             :     GByte abyHeader[16];
     192             : 
     193             :     /* -------------------------------------------------------------------- */
     194             :     /*      Try to open the imagery file.                                   */
     195             :     /* -------------------------------------------------------------------- */
     196           4 :     fp = VSIFOpenL(pszFilename, pszAccess);
     197             : 
     198           4 :     if (fp == NULL)
     199             :     {
     200           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     201             :                  "Failed to open CEOS file `%s' with access `%s'.\n",
     202             :                  pszFilename, pszAccess);
     203           0 :         return NULL;
     204             :     }
     205             : 
     206             :     /* -------------------------------------------------------------------- */
     207             :     /*      Create a CEOSImage structure, and initialize it.                */
     208             :     /* -------------------------------------------------------------------- */
     209           4 :     psImage = (CEOSImage *)CPLCalloc(1, sizeof(CEOSImage));
     210           4 :     psImage->fpImage = fp;
     211             : 
     212           4 :     psImage->nPixels = psImage->nLines = psImage->nBands = 0;
     213             : 
     214             :     /* -------------------------------------------------------------------- */
     215             :     /*      Preread info on the first record, to establish if it is         */
     216             :     /*      little endian.                                                  */
     217             :     /* -------------------------------------------------------------------- */
     218           4 :     if (VSIFReadL(abyHeader, 16, 1, fp) != 1 || VSIFSeekL(fp, 0, SEEK_SET) < 0)
     219             :     {
     220           0 :         CEOSClose(psImage);
     221           0 :         return NULL;
     222             :     }
     223             : 
     224           4 :     if (abyHeader[0] != 0 || abyHeader[1] != 0)
     225           2 :         psImage->bLittleEndian = TRUE;
     226             : 
     227             :     /* -------------------------------------------------------------------- */
     228             :     /*      Try to read the header record.                                  */
     229             :     /* -------------------------------------------------------------------- */
     230           4 :     psRecord = CEOSReadRecord(psImage);
     231           4 :     if (psRecord == NULL || psRecord->nLength < 288 + 4)
     232             :     {
     233           0 :         CEOSDestroyRecord(psRecord);
     234           0 :         CEOSClose(psImage);
     235           0 :         return NULL;
     236             :     }
     237             : 
     238           4 :     char format_doc[13] = {0};
     239           4 :     memcpy(format_doc, psRecord->pachData + 16, 12);
     240           4 :     if (strncmp("CEOS-SAR-CCT", format_doc, 12) == 0)
     241             :     {
     242           2 :         CEOSDestroyRecord(psRecord);
     243           2 :         CEOSClose(psImage);
     244           2 :         return NULL;
     245             :     }
     246             : 
     247           2 :     if (psRecord->nRecordType != CRT_IMAGE_FDR)
     248             :     {
     249           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     250             :                  "Got a %X type record, instead of the expected\n"
     251             :                  "file descriptor record on file %s.\n",
     252             :                  psRecord->nRecordType, pszFilename);
     253             : 
     254           0 :         CEOSDestroyRecord(psRecord);
     255           0 :         CEOSClose(psImage);
     256           0 :         return NULL;
     257             :     }
     258             : 
     259             :     /* -------------------------------------------------------------------- */
     260             :     /*      The sequence number should be 2 indicating this is the          */
     261             :     /*      imagery file.                                                   */
     262             :     /* -------------------------------------------------------------------- */
     263           2 :     nSeqNum = CEOSScanInt(psRecord->pachData + 44, 4);
     264           2 :     if (nSeqNum != 2)
     265             :     {
     266           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     267             :                  "Got a %d file sequence number, instead of the expected\n"
     268             :                  "2 indicating imagery on file %s.\n"
     269             :                  "Continuing to access anyways.\n",
     270             :                  nSeqNum, pszFilename);
     271             :     }
     272             : 
     273             :     /* -------------------------------------------------------------------- */
     274             :     /*      Extract various information.                                    */
     275             :     /* -------------------------------------------------------------------- */
     276           2 :     psImage->nImageRecCount = CEOSScanInt(psRecord->pachData + 180, 6);
     277           2 :     psImage->nImageRecLength = CEOSScanInt(psRecord->pachData + 186, 6);
     278           2 :     psImage->nBitsPerPixel = CEOSScanInt(psRecord->pachData + 216, 4);
     279           2 :     psImage->nBands = CEOSScanInt(psRecord->pachData + 232, 4);
     280           2 :     psImage->nLines = CEOSScanInt(psRecord->pachData + 236, 8);
     281           2 :     psImage->nPixels = CEOSScanInt(psRecord->pachData + 248, 8);
     282             : 
     283           2 :     psImage->nPrefixBytes = CEOSScanInt(psRecord->pachData + 276, 4);
     284           2 :     psImage->nSuffixBytes = CEOSScanInt(psRecord->pachData + 288, 4);
     285             : 
     286           2 :     if (psImage->nImageRecLength <= 0 || psImage->nPrefixBytes < 0 ||
     287           2 :         psImage->nBands > INT_MAX / psImage->nImageRecLength ||
     288           2 :         (size_t)psImage->nBands > INT_MAX / sizeof(int))
     289             :     {
     290           0 :         CEOSDestroyRecord(psRecord);
     291           0 :         CEOSClose(psImage);
     292           0 :         return NULL;
     293             :     }
     294             : 
     295             :     /* -------------------------------------------------------------------- */
     296             :     /*      Try to establish the layout of the imagery data.                */
     297             :     /* -------------------------------------------------------------------- */
     298           2 :     psImage->nLineOffset = psImage->nBands * psImage->nImageRecLength;
     299             : 
     300           2 :     psImage->panDataStart = (int *)VSIMalloc(sizeof(int) * psImage->nBands);
     301           2 :     if (psImage->panDataStart == NULL)
     302             :     {
     303           0 :         CEOSDestroyRecord(psRecord);
     304           0 :         CEOSClose(psImage);
     305           0 :         return NULL;
     306             :     }
     307             : 
     308          10 :     for (i = 0; i < psImage->nBands; i++)
     309             :     {
     310           8 :         psImage->panDataStart[i] = psRecord->nLength +
     311           8 :                                    i * psImage->nImageRecLength + 12 +
     312           8 :                                    psImage->nPrefixBytes;
     313             :     }
     314             : 
     315           2 :     CEOSDestroyRecord(psRecord);
     316             : 
     317           2 :     return psImage;
     318             : }
     319             : 
     320             : /************************************************************************/
     321             : /*                          CEOSReadScanline()                          */
     322             : /************************************************************************/
     323             : 
     324             : /**
     325             :  * Read a scanline of image.
     326             :  *
     327             :  * @param psCEOS The CEOS dataset handle returned by CEOSOpen().
     328             :  * @param nBand The band number (i.e. 1, 2, 3).
     329             :  * @param nScanline The scanline requested, one based.
     330             :  * @param pData The data buffer to read into.  Must be at least nPixels *
     331             :  * nBitesPerPixel bits long.
     332             :  *
     333             :  * @return CPLErr Returns error indicator or CE_None if the read succeeds.
     334             :  */
     335             : 
     336           3 : CPLErr CEOSReadScanline(CEOSImage *psCEOS, int nBand, int nScanline,
     337             :                         void *pData)
     338             : 
     339             : {
     340             :     int nOffset, nBytes;
     341             : 
     342             :     /*
     343             :      * As a short cut, I currently just seek to the data, and read it
     344             :      * raw, rather than trying to read ceos records properly.
     345             :      */
     346             : 
     347           3 :     nOffset =
     348           3 :         psCEOS->panDataStart[nBand - 1] + (nScanline - 1) * psCEOS->nLineOffset;
     349             : 
     350           3 :     if (VSIFSeekL(psCEOS->fpImage, nOffset, SEEK_SET) != 0)
     351             :     {
     352           0 :         CPLError(CE_Failure, CPLE_FileIO,
     353             :                  "Seek to %d for scanline %d failed.\n", nOffset, nScanline);
     354           0 :         return CE_Failure;
     355             :     }
     356             : 
     357             :     /* -------------------------------------------------------------------- */
     358             :     /*      Read the data.                                                  */
     359             :     /* -------------------------------------------------------------------- */
     360           3 :     nBytes = psCEOS->nPixels * psCEOS->nBitsPerPixel / 8;
     361           3 :     if ((int)VSIFReadL(pData, 1, nBytes, psCEOS->fpImage) != nBytes)
     362             :     {
     363           0 :         CPLError(CE_Failure, CPLE_FileIO,
     364             :                  "Read of %d bytes for scanline %d failed.\n", nBytes,
     365             :                  nScanline);
     366           0 :         return CE_Failure;
     367             :     }
     368             : 
     369           3 :     return CE_None;
     370             : }
     371             : 
     372             : /************************************************************************/
     373             : /*                             CEOSClose()                              */
     374             : /************************************************************************/
     375             : 
     376             : /**
     377             :  * Close a CEOS transfer.  Any open files are closed, and memory deallocated.
     378             :  *
     379             :  * @param psCEOS The CEOSImage handle from CEOSOpen to be closed.
     380             :  */
     381             : 
     382           4 : void CEOSClose(CEOSImage *psCEOS)
     383             : 
     384             : {
     385           4 :     CPLFree(psCEOS->panDataStart);
     386           4 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(psCEOS->fpImage));
     387           4 :     CPLFree(psCEOS);
     388           4 : }

Generated by: LCOV version 1.14