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

Generated by: LCOV version 1.14