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: 2025-01-18 12:42:00 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.14