LCOV - code coverage report
Current view: top level - frmts/raw - krodataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 119 134 88.8 %
Date: 2025-10-19 15:46:27 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  KRO format reader/writer
       4             :  * Purpose:  Implementation of KOLOR Raw Format
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  * Financial Support: SITES (http://www.sites.fr)
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "gdal_frmts.h"
      16             : #include "gdal_priv.h"
      17             : #include "rawdataset.h"
      18             : 
      19             : #include <algorithm>
      20             : 
      21             : // http://www.autopano.net/wiki-en/Format_KRO
      22             : 
      23             : /************************************************************************/
      24             : /* ==================================================================== */
      25             : /*                                KRODataset                            */
      26             : /* ==================================================================== */
      27             : /************************************************************************/
      28             : 
      29             : class KRODataset final : public RawDataset
      30             : {
      31             :     VSILFILE *fpImage = nullptr;  // image data file.
      32             : 
      33             :     CPL_DISALLOW_COPY_ASSIGN(KRODataset)
      34             : 
      35             :     CPLErr Close() override;
      36             : 
      37             :   public:
      38          37 :     KRODataset() = default;
      39             :     ~KRODataset() override;
      40             : 
      41             :     static GDALDataset *Open(GDALOpenInfo *);
      42             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
      43             :                                int nBandsIn, GDALDataType eType,
      44             :                                char **papszOptions);
      45             :     static int Identify(GDALOpenInfo *);
      46             : };
      47             : 
      48             : /************************************************************************/
      49             : /* ==================================================================== */
      50             : /*                                  KRODataset                          */
      51             : /* ==================================================================== */
      52             : /************************************************************************/
      53             : 
      54             : /************************************************************************/
      55             : /*                             ~KRODataset()                            */
      56             : /************************************************************************/
      57             : 
      58          74 : KRODataset::~KRODataset()
      59             : 
      60             : {
      61          37 :     KRODataset::Close();
      62          74 : }
      63             : 
      64             : /************************************************************************/
      65             : /*                              Close()                                 */
      66             : /************************************************************************/
      67             : 
      68          74 : CPLErr KRODataset::Close()
      69             : {
      70          74 :     CPLErr eErr = CE_None;
      71          74 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
      72             :     {
      73          37 :         if (KRODataset::FlushCache(true) != CE_None)
      74           0 :             eErr = CE_Failure;
      75             : 
      76          37 :         if (fpImage)
      77             :         {
      78          37 :             if (VSIFCloseL(fpImage) != 0)
      79             :             {
      80           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
      81           0 :                 eErr = CE_Failure;
      82             :             }
      83             :         }
      84             : 
      85          37 :         if (GDALPamDataset::Close() != CE_None)
      86           0 :             eErr = CE_Failure;
      87             :     }
      88          74 :     return eErr;
      89             : }
      90             : 
      91             : /************************************************************************/
      92             : /*                              Identify()                              */
      93             : /************************************************************************/
      94             : 
      95       59028 : int KRODataset::Identify(GDALOpenInfo *poOpenInfo)
      96             : 
      97             : {
      98       59028 :     if (poOpenInfo->nHeaderBytes < 20)
      99       55242 :         return FALSE;
     100             : 
     101        3786 :     if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     102             :                         "KRO\x01"))
     103        3712 :         return FALSE;
     104             : 
     105          74 :     return TRUE;
     106             : }
     107             : 
     108             : /************************************************************************/
     109             : /*                                Open()                                */
     110             : /************************************************************************/
     111             : 
     112          37 : GDALDataset *KRODataset::Open(GDALOpenInfo *poOpenInfo)
     113             : 
     114             : {
     115          37 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     116           0 :         return nullptr;
     117             : 
     118             :     /* -------------------------------------------------------------------- */
     119             :     /*      Create a corresponding GDALDataset.                             */
     120             :     /* -------------------------------------------------------------------- */
     121          74 :     auto poDS = std::make_unique<KRODataset>();
     122          37 :     poDS->eAccess = poOpenInfo->eAccess;
     123          37 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
     124             : 
     125             :     /* -------------------------------------------------------------------- */
     126             :     /*      Read the file header.                                           */
     127             :     /* -------------------------------------------------------------------- */
     128          37 :     char achHeader[20] = {'\0'};
     129          37 :     CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 20, poDS->fpImage));
     130             : 
     131             :     int nXSize;
     132          37 :     memcpy(&nXSize, achHeader + 4, 4);
     133          37 :     CPL_MSBPTR32(&nXSize);
     134             : 
     135          37 :     int nYSize = 0;
     136          37 :     memcpy(&nYSize, achHeader + 8, 4);
     137          37 :     CPL_MSBPTR32(&nYSize);
     138             : 
     139          37 :     int nDepth = 0;
     140          37 :     memcpy(&nDepth, achHeader + 12, 4);
     141          37 :     CPL_MSBPTR32(&nDepth);
     142             : 
     143          37 :     int nComp = 0;
     144          37 :     memcpy(&nComp, achHeader + 16, 4);
     145          37 :     CPL_MSBPTR32(&nComp);
     146             : 
     147          74 :     if (!GDALCheckDatasetDimensions(nXSize, nYSize) ||
     148          37 :         !GDALCheckBandCount(nComp, FALSE))
     149             :     {
     150           0 :         return nullptr;
     151             :     }
     152             : 
     153          37 :     poDS->nRasterXSize = nXSize;
     154          37 :     poDS->nRasterYSize = nYSize;
     155             : 
     156          37 :     GDALDataType eDT = GDT_Unknown;
     157          37 :     if (nDepth == 8)
     158             :     {
     159          18 :         eDT = GDT_Byte;
     160             :     }
     161          19 :     else if (nDepth == 16)
     162             :     {
     163          11 :         eDT = GDT_UInt16;
     164             :     }
     165           8 :     else if (nDepth == 32)
     166             :     {
     167           8 :         eDT = GDT_Float32;
     168             :     }
     169             :     else
     170             :     {
     171           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unhandled depth : %d", nDepth);
     172           0 :         return nullptr;
     173             :     }
     174             : 
     175          37 :     const int nDataTypeSize = nDepth / 8;
     176             : 
     177          74 :     if (nComp == 0 || nDataTypeSize == 0 ||
     178          37 :         poDS->nRasterXSize > INT_MAX / (nComp * nDataTypeSize))
     179             :     {
     180           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     181             :                  "Too large width / number of bands");
     182           0 :         return nullptr;
     183             :     }
     184             : 
     185          37 :     vsi_l_offset nExpectedSize = static_cast<vsi_l_offset>(poDS->nRasterXSize) *
     186          37 :                                      poDS->nRasterYSize * nComp *
     187          37 :                                      nDataTypeSize +
     188          37 :                                  20;
     189          37 :     VSIFSeekL(poDS->fpImage, 0, SEEK_END);
     190          37 :     if (VSIFTellL(poDS->fpImage) < nExpectedSize)
     191             :     {
     192           0 :         CPLError(CE_Failure, CPLE_FileIO, "File too short");
     193           0 :         return nullptr;
     194             :     }
     195             : 
     196             :     /* -------------------------------------------------------------------- */
     197             :     /*      Create bands.                                                   */
     198             :     /* -------------------------------------------------------------------- */
     199         112 :     for (int iBand = 0; iBand < nComp; iBand++)
     200             :     {
     201             :         auto poBand = RawRasterBand::Create(
     202         150 :             poDS.get(), iBand + 1, poDS->fpImage, 20 + nDataTypeSize * iBand,
     203          75 :             nComp * nDataTypeSize, poDS->nRasterXSize * nComp * nDataTypeSize,
     204             :             eDT, RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
     205          75 :             RawRasterBand::OwnFP::NO);
     206          75 :         if (!poBand)
     207           0 :             return nullptr;
     208          75 :         if (nComp == 3 || nComp == 4)
     209             :         {
     210          33 :             poBand->SetColorInterpretation(
     211          33 :                 static_cast<GDALColorInterp>(GCI_RedBand + iBand));
     212             :         }
     213          75 :         poDS->SetBand(iBand + 1, std::move(poBand));
     214             :     }
     215             : 
     216          37 :     if (nComp > 1)
     217          16 :         poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
     218             : 
     219             :     /* -------------------------------------------------------------------- */
     220             :     /*      Initialize any PAM information.                                 */
     221             :     /* -------------------------------------------------------------------- */
     222          37 :     poDS->SetDescription(poOpenInfo->pszFilename);
     223          37 :     poDS->TryLoadXML();
     224             : 
     225             :     /* -------------------------------------------------------------------- */
     226             :     /*      Check for overviews.                                            */
     227             :     /* -------------------------------------------------------------------- */
     228          37 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     229             : 
     230          37 :     return poDS.release();
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                               Create()                               */
     235             : /************************************************************************/
     236             : 
     237          64 : GDALDataset *KRODataset::Create(const char *pszFilename, int nXSize, int nYSize,
     238             :                                 int nBandsIn, GDALDataType eType,
     239             :                                 char ** /* papszOptions */)
     240             : {
     241          64 :     if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Float32)
     242             :     {
     243          30 :         CPLError(CE_Failure, CPLE_AppDefined,
     244             :                  "Attempt to create KRO file with unsupported data type '%s'.",
     245             :                  GDALGetDataTypeName(eType));
     246          30 :         return nullptr;
     247             :     }
     248          34 :     if (nXSize == 0 || nYSize == 0 || nBandsIn == 0)
     249             :     {
     250           1 :         return nullptr;
     251             :     }
     252             : 
     253             :     /* -------------------------------------------------------------------- */
     254             :     /*      Try to create file.                                             */
     255             :     /* -------------------------------------------------------------------- */
     256          33 :     VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
     257          33 :     if (fp == nullptr)
     258             :     {
     259           3 :         CPLError(CE_Failure, CPLE_OpenFailed,
     260             :                  "Attempt to create file `%s' failed.", pszFilename);
     261           3 :         return nullptr;
     262             :     }
     263             : 
     264          30 :     size_t nRet = VSIFWriteL("KRO\01", 4, 1, fp);
     265             : 
     266             :     /* -------------------------------------------------------------------- */
     267             :     /*      Create a file level header.                                     */
     268             :     /* -------------------------------------------------------------------- */
     269          30 :     int nTmp = nXSize;
     270          30 :     CPL_MSBPTR32(&nTmp);
     271          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     272             : 
     273          30 :     nTmp = nYSize;
     274          30 :     CPL_MSBPTR32(&nTmp);
     275          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     276             : 
     277          30 :     nTmp = GDALGetDataTypeSizeBits(eType);
     278          30 :     CPL_MSBPTR32(&nTmp);
     279          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     280             : 
     281          30 :     nTmp = nBandsIn;
     282          30 :     CPL_MSBPTR32(&nTmp);
     283          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     284             : 
     285             :     /* -------------------------------------------------------------------- */
     286             :     /*      Zero out image data                                             */
     287             :     /* -------------------------------------------------------------------- */
     288             : 
     289          30 :     CPL_IGNORE_RET_VAL(VSIFSeekL(fp,
     290          60 :                                  static_cast<vsi_l_offset>(nXSize) * nYSize *
     291          30 :                                          GDALGetDataTypeSizeBytes(eType) *
     292          30 :                                          nBandsIn -
     293             :                                      1,
     294             :                                  SEEK_CUR));
     295          30 :     GByte byNul = 0;
     296          30 :     nRet += VSIFWriteL(&byNul, 1, 1, fp);
     297          30 :     if (VSIFCloseL(fp) != 0)
     298             :     {
     299           0 :         CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     300           0 :         return nullptr;
     301             :     }
     302             : 
     303          30 :     if (nRet != 6)
     304          10 :         return nullptr;
     305             : 
     306          20 :     return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
     307             : }
     308             : 
     309             : /************************************************************************/
     310             : /*                         GDALRegister_KRO()                           */
     311             : /************************************************************************/
     312             : 
     313        2033 : void GDALRegister_KRO()
     314             : 
     315             : {
     316        2033 :     if (GDALGetDriverByName("KRO") != nullptr)
     317         283 :         return;
     318             : 
     319        1750 :     GDALDriver *poDriver = new GDALDriver();
     320             : 
     321        1750 :     poDriver->SetDescription("KRO");
     322        1750 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     323        1750 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "KOLOR Raw");
     324        1750 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kro");
     325        1750 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     326        1750 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     327        1750 :                               "Byte UInt16 Float32");
     328             : 
     329        1750 :     poDriver->pfnIdentify = KRODataset::Identify;
     330        1750 :     poDriver->pfnOpen = KRODataset::Open;
     331        1750 :     poDriver->pfnCreate = KRODataset::Create;
     332             : 
     333        1750 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     334             : }

Generated by: LCOV version 1.14