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

Generated by: LCOV version 1.14