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-05-03 15:49:35 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_string.h"
      31             : #include "gdal_frmts.h"
      32             : #include "rawdataset.h"
      33             : 
      34             : #include <algorithm>
      35             : 
      36             : // http://www.autopano.net/wiki-en/Format_KRO
      37             : 
      38             : /************************************************************************/
      39             : /* ==================================================================== */
      40             : /*                                KRODataset                            */
      41             : /* ==================================================================== */
      42             : /************************************************************************/
      43             : 
      44             : class KRODataset final : public RawDataset
      45             : {
      46             :     VSILFILE *fpImage = nullptr;  // image data file.
      47             : 
      48             :     CPL_DISALLOW_COPY_ASSIGN(KRODataset)
      49             : 
      50             :     CPLErr Close() override;
      51             : 
      52             :   public:
      53          37 :     KRODataset() = default;
      54             :     ~KRODataset();
      55             : 
      56             :     static GDALDataset *Open(GDALOpenInfo *);
      57             :     static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
      58             :                                int nBandsIn, GDALDataType eType,
      59             :                                char **papszOptions);
      60             :     static int Identify(GDALOpenInfo *);
      61             : };
      62             : 
      63             : /************************************************************************/
      64             : /* ==================================================================== */
      65             : /*                                  KRODataset                          */
      66             : /* ==================================================================== */
      67             : /************************************************************************/
      68             : 
      69             : /************************************************************************/
      70             : /*                             ~KRODataset()                            */
      71             : /************************************************************************/
      72             : 
      73          74 : KRODataset::~KRODataset()
      74             : 
      75             : {
      76          37 :     KRODataset::Close();
      77          74 : }
      78             : 
      79             : /************************************************************************/
      80             : /*                              Close()                                 */
      81             : /************************************************************************/
      82             : 
      83          74 : CPLErr KRODataset::Close()
      84             : {
      85          74 :     CPLErr eErr = CE_None;
      86          74 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
      87             :     {
      88          37 :         if (KRODataset::FlushCache(true) != CE_None)
      89           0 :             eErr = CE_Failure;
      90             : 
      91          37 :         if (fpImage)
      92             :         {
      93          37 :             if (VSIFCloseL(fpImage) != 0)
      94             :             {
      95           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
      96           0 :                 eErr = CE_Failure;
      97             :             }
      98             :         }
      99             : 
     100          37 :         if (GDALPamDataset::Close() != CE_None)
     101           0 :             eErr = CE_Failure;
     102             :     }
     103          74 :     return eErr;
     104             : }
     105             : 
     106             : /************************************************************************/
     107             : /*                              Identify()                              */
     108             : /************************************************************************/
     109             : 
     110       48784 : int KRODataset::Identify(GDALOpenInfo *poOpenInfo)
     111             : 
     112             : {
     113       48784 :     if (poOpenInfo->nHeaderBytes < 20)
     114       45492 :         return FALSE;
     115             : 
     116        3292 :     if (!STARTS_WITH_CI(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
     117             :                         "KRO\x01"))
     118        3218 :         return FALSE;
     119             : 
     120          74 :     return TRUE;
     121             : }
     122             : 
     123             : /************************************************************************/
     124             : /*                                Open()                                */
     125             : /************************************************************************/
     126             : 
     127          37 : GDALDataset *KRODataset::Open(GDALOpenInfo *poOpenInfo)
     128             : 
     129             : {
     130          37 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     131           0 :         return nullptr;
     132             : 
     133             :     /* -------------------------------------------------------------------- */
     134             :     /*      Create a corresponding GDALDataset.                             */
     135             :     /* -------------------------------------------------------------------- */
     136          74 :     auto poDS = std::make_unique<KRODataset>();
     137          37 :     poDS->eAccess = poOpenInfo->eAccess;
     138          37 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
     139             : 
     140             :     /* -------------------------------------------------------------------- */
     141             :     /*      Read the file header.                                           */
     142             :     /* -------------------------------------------------------------------- */
     143          37 :     char achHeader[20] = {'\0'};
     144          37 :     CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 20, poDS->fpImage));
     145             : 
     146             :     int nXSize;
     147          37 :     memcpy(&nXSize, achHeader + 4, 4);
     148          37 :     CPL_MSBPTR32(&nXSize);
     149             : 
     150          37 :     int nYSize = 0;
     151          37 :     memcpy(&nYSize, achHeader + 8, 4);
     152          37 :     CPL_MSBPTR32(&nYSize);
     153             : 
     154          37 :     int nDepth = 0;
     155          37 :     memcpy(&nDepth, achHeader + 12, 4);
     156          37 :     CPL_MSBPTR32(&nDepth);
     157             : 
     158          37 :     int nComp = 0;
     159          37 :     memcpy(&nComp, achHeader + 16, 4);
     160          37 :     CPL_MSBPTR32(&nComp);
     161             : 
     162          74 :     if (!GDALCheckDatasetDimensions(nXSize, nYSize) ||
     163          37 :         !GDALCheckBandCount(nComp, FALSE))
     164             :     {
     165           0 :         return nullptr;
     166             :     }
     167             : 
     168          37 :     poDS->nRasterXSize = nXSize;
     169          37 :     poDS->nRasterYSize = nYSize;
     170             : 
     171          37 :     GDALDataType eDT = GDT_Unknown;
     172          37 :     if (nDepth == 8)
     173             :     {
     174          18 :         eDT = GDT_Byte;
     175             :     }
     176          19 :     else if (nDepth == 16)
     177             :     {
     178          11 :         eDT = GDT_UInt16;
     179             :     }
     180           8 :     else if (nDepth == 32)
     181             :     {
     182           8 :         eDT = GDT_Float32;
     183             :     }
     184             :     else
     185             :     {
     186           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Unhandled depth : %d", nDepth);
     187           0 :         return nullptr;
     188             :     }
     189             : 
     190          37 :     const int nDataTypeSize = nDepth / 8;
     191             : 
     192          74 :     if (nComp == 0 || nDataTypeSize == 0 ||
     193          37 :         poDS->nRasterXSize > INT_MAX / (nComp * nDataTypeSize))
     194             :     {
     195           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     196             :                  "Too large width / number of bands");
     197           0 :         return nullptr;
     198             :     }
     199             : 
     200          37 :     vsi_l_offset nExpectedSize = static_cast<vsi_l_offset>(poDS->nRasterXSize) *
     201          37 :                                      poDS->nRasterYSize * nComp *
     202          37 :                                      nDataTypeSize +
     203          37 :                                  20;
     204          37 :     VSIFSeekL(poDS->fpImage, 0, SEEK_END);
     205          37 :     if (VSIFTellL(poDS->fpImage) < nExpectedSize)
     206             :     {
     207           0 :         CPLError(CE_Failure, CPLE_FileIO, "File too short");
     208           0 :         return nullptr;
     209             :     }
     210             : 
     211             :     /* -------------------------------------------------------------------- */
     212             :     /*      Create bands.                                                   */
     213             :     /* -------------------------------------------------------------------- */
     214         112 :     for (int iBand = 0; iBand < nComp; iBand++)
     215             :     {
     216             :         auto poBand = RawRasterBand::Create(
     217         150 :             poDS.get(), iBand + 1, poDS->fpImage, 20 + nDataTypeSize * iBand,
     218          75 :             nComp * nDataTypeSize, poDS->nRasterXSize * nComp * nDataTypeSize,
     219             :             eDT, RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
     220          75 :             RawRasterBand::OwnFP::NO);
     221          75 :         if (!poBand)
     222           0 :             return nullptr;
     223          75 :         if (nComp == 3 || nComp == 4)
     224             :         {
     225          33 :             poBand->SetColorInterpretation(
     226          33 :                 static_cast<GDALColorInterp>(GCI_RedBand + iBand));
     227             :         }
     228          75 :         poDS->SetBand(iBand + 1, std::move(poBand));
     229             :     }
     230             : 
     231          37 :     if (nComp > 1)
     232          16 :         poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
     233             : 
     234             :     /* -------------------------------------------------------------------- */
     235             :     /*      Initialize any PAM information.                                 */
     236             :     /* -------------------------------------------------------------------- */
     237          37 :     poDS->SetDescription(poOpenInfo->pszFilename);
     238          37 :     poDS->TryLoadXML();
     239             : 
     240             :     /* -------------------------------------------------------------------- */
     241             :     /*      Check for overviews.                                            */
     242             :     /* -------------------------------------------------------------------- */
     243          37 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     244             : 
     245          37 :     return poDS.release();
     246             : }
     247             : 
     248             : /************************************************************************/
     249             : /*                               Create()                               */
     250             : /************************************************************************/
     251             : 
     252          64 : GDALDataset *KRODataset::Create(const char *pszFilename, int nXSize, int nYSize,
     253             :                                 int nBandsIn, GDALDataType eType,
     254             :                                 char ** /* papszOptions */)
     255             : {
     256          64 :     if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Float32)
     257             :     {
     258          30 :         CPLError(CE_Failure, CPLE_AppDefined,
     259             :                  "Attempt to create KRO file with unsupported data type '%s'.",
     260             :                  GDALGetDataTypeName(eType));
     261          30 :         return nullptr;
     262             :     }
     263          34 :     if (nXSize == 0 || nYSize == 0 || nBandsIn == 0)
     264             :     {
     265           1 :         return nullptr;
     266             :     }
     267             : 
     268             :     /* -------------------------------------------------------------------- */
     269             :     /*      Try to create file.                                             */
     270             :     /* -------------------------------------------------------------------- */
     271          33 :     VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
     272          33 :     if (fp == nullptr)
     273             :     {
     274           3 :         CPLError(CE_Failure, CPLE_OpenFailed,
     275             :                  "Attempt to create file `%s' failed.", pszFilename);
     276           3 :         return nullptr;
     277             :     }
     278             : 
     279          30 :     size_t nRet = VSIFWriteL("KRO\01", 4, 1, fp);
     280             : 
     281             :     /* -------------------------------------------------------------------- */
     282             :     /*      Create a file level header.                                     */
     283             :     /* -------------------------------------------------------------------- */
     284          30 :     int nTmp = nXSize;
     285          30 :     CPL_MSBPTR32(&nTmp);
     286          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     287             : 
     288          30 :     nTmp = nYSize;
     289          30 :     CPL_MSBPTR32(&nTmp);
     290          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     291             : 
     292          30 :     nTmp = GDALGetDataTypeSizeBits(eType);
     293          30 :     CPL_MSBPTR32(&nTmp);
     294          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     295             : 
     296          30 :     nTmp = nBandsIn;
     297          30 :     CPL_MSBPTR32(&nTmp);
     298          30 :     nRet += VSIFWriteL(&nTmp, 4, 1, fp);
     299             : 
     300             :     /* -------------------------------------------------------------------- */
     301             :     /*      Zero out image data                                             */
     302             :     /* -------------------------------------------------------------------- */
     303             : 
     304          30 :     CPL_IGNORE_RET_VAL(VSIFSeekL(fp,
     305          60 :                                  static_cast<vsi_l_offset>(nXSize) * nYSize *
     306          30 :                                          GDALGetDataTypeSizeBytes(eType) *
     307          30 :                                          nBandsIn -
     308             :                                      1,
     309             :                                  SEEK_CUR));
     310          30 :     GByte byNul = 0;
     311          30 :     nRet += VSIFWriteL(&byNul, 1, 1, fp);
     312          30 :     if (VSIFCloseL(fp) != 0)
     313             :     {
     314           0 :         CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     315           0 :         return nullptr;
     316             :     }
     317             : 
     318          30 :     if (nRet != 6)
     319          10 :         return nullptr;
     320             : 
     321          20 :     return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update));
     322             : }
     323             : 
     324             : /************************************************************************/
     325             : /*                         GDALRegister_KRO()                           */
     326             : /************************************************************************/
     327             : 
     328        1511 : void GDALRegister_KRO()
     329             : 
     330             : {
     331        1511 :     if (GDALGetDriverByName("KRO") != nullptr)
     332         295 :         return;
     333             : 
     334        1216 :     GDALDriver *poDriver = new GDALDriver();
     335             : 
     336        1216 :     poDriver->SetDescription("KRO");
     337        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     338        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "KOLOR Raw");
     339        1216 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "kro");
     340        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     341        1216 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
     342        1216 :                               "Byte UInt16 Float32");
     343             : 
     344        1216 :     poDriver->pfnIdentify = KRODataset::Identify;
     345        1216 :     poDriver->pfnOpen = KRODataset::Open;
     346        1216 :     poDriver->pfnCreate = KRODataset::Create;
     347             : 
     348        1216 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     349             : }

Generated by: LCOV version 1.14