LCOV - code coverage report
Current view: top level - apps - gdalalg_compare_common.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 49 54 90.7 %
Date: 2026-06-23 16:35:19 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Common code between raster compare and mdim compare
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2026, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_compare_common.h"
      14             : #include "gdalalgorithm.h"
      15             : #include "gdal_dataset.h"
      16             : #include "gdal_driver.h"
      17             : 
      18             : #include "cpl_vsi_virtual.h"
      19             : 
      20             : //! @cond Doxygen_Suppress
      21             : 
      22             : GDALCompareCommon::GDALCompareCommon() = default;
      23             : 
      24             : GDALCompareCommon::~GDALCompareCommon() = default;
      25             : 
      26             : /************************************************************************/
      27             : /*            GDALRasterCompareAlgorithm::BinaryComparison()            */
      28             : /************************************************************************/
      29             : 
      30             : /* static */
      31          13 : bool GDALCompareCommon::BinaryComparison(GDALAlgorithm *alg,
      32             :                                          std::vector<std::string> &aosReport,
      33             :                                          GDALDataset *poRefDS,
      34             :                                          GDALDataset *poInputDS)
      35             : {
      36          13 :     if (poRefDS->GetDescription()[0] == 0)
      37             :     {
      38           1 :         alg->ReportError(
      39             :             CE_Warning, CPLE_AppDefined,
      40             :             "Reference dataset has no name. Skipping binary file comparison");
      41           1 :         return false;
      42             :     }
      43             : 
      44          12 :     auto poRefDrv = poRefDS->GetDriver();
      45          12 :     if (poRefDrv && EQUAL(poRefDrv->GetDescription(), "MEM"))
      46             :     {
      47           1 :         alg->ReportError(
      48             :             CE_Warning, CPLE_AppDefined,
      49             :             "Reference dataset is a in-memory dataset. Skipping binary "
      50             :             "file comparison");
      51           1 :         return false;
      52             :     }
      53             : 
      54          11 :     if (poInputDS->GetDescription()[0] == 0)
      55             :     {
      56           1 :         alg->ReportError(
      57             :             CE_Warning, CPLE_AppDefined,
      58             :             "Input dataset has no name. Skipping binary file comparison");
      59           1 :         return false;
      60             :     }
      61             : 
      62          10 :     auto poInputDrv = poInputDS->GetDriver();
      63          10 :     if (poInputDrv && EQUAL(poInputDrv->GetDescription(), "MEM"))
      64             :     {
      65           1 :         alg->ReportError(
      66             :             CE_Warning, CPLE_AppDefined,
      67             :             "Input dataset is a in-memory dataset. Skipping binary "
      68             :             "file comparison");
      69           1 :         return false;
      70             :     }
      71             : 
      72          18 :     VSIVirtualHandleUniquePtr fpRef(VSIFOpenL(poRefDS->GetDescription(), "rb"));
      73             :     VSIVirtualHandleUniquePtr fpInput(
      74          18 :         VSIFOpenL(poInputDS->GetDescription(), "rb"));
      75           9 :     if (!fpRef)
      76             :     {
      77           1 :         alg->ReportError(
      78             :             CE_Warning, CPLE_AppDefined,
      79             :             "Reference dataset '%s' is not a file. Skipping binary "
      80             :             "file comparison",
      81           1 :             poRefDS->GetDescription());
      82           1 :         return false;
      83             :     }
      84             : 
      85           8 :     if (!fpInput)
      86             :     {
      87           1 :         alg->ReportError(
      88             :             CE_Warning, CPLE_AppDefined,
      89             :             "Input dataset '%s' is not a file. Skipping binary file comparison",
      90           1 :             poInputDS->GetDescription());
      91           1 :         return false;
      92             :     }
      93             : 
      94           7 :     fpRef->Seek(0, SEEK_END);
      95           7 :     fpInput->Seek(0, SEEK_END);
      96           7 :     const auto nRefSize = fpRef->Tell();
      97           7 :     const auto nInputSize = fpInput->Tell();
      98           7 :     if (nRefSize != nInputSize)
      99             :     {
     100           4 :         aosReport.push_back("Reference file has size " +
     101           6 :                             std::to_string(nRefSize) +
     102           4 :                             " bytes, whereas input file has size " +
     103           8 :                             std::to_string(nInputSize) + " bytes.");
     104             : 
     105           2 :         return false;
     106             :     }
     107             : 
     108           5 :     constexpr size_t BUF_SIZE = 1024 * 1024;
     109          10 :     std::vector<GByte> abyRef(BUF_SIZE);
     110          10 :     std::vector<GByte> abyInput(BUF_SIZE);
     111             : 
     112           5 :     fpRef->Seek(0, SEEK_SET);
     113           5 :     fpInput->Seek(0, SEEK_SET);
     114             : 
     115           0 :     do
     116             :     {
     117           5 :         const size_t nRefRead = fpRef->Read(abyRef.data(), 1, BUF_SIZE);
     118           5 :         const size_t nInputRead = fpInput->Read(abyInput.data(), 1, BUF_SIZE);
     119             : 
     120           5 :         if (nRefRead != BUF_SIZE && fpRef->Tell() != nRefSize)
     121             :         {
     122           0 :             aosReport.push_back("Failed to fully read reference file");
     123           0 :             return false;
     124             :         }
     125             : 
     126           5 :         if (nInputRead != BUF_SIZE && fpInput->Tell() != nRefSize)
     127             :         {
     128           0 :             aosReport.push_back("Failed to fully read input file");
     129           0 :             return false;
     130             :         }
     131             : 
     132           5 :         if (abyRef != abyInput)
     133             :         {
     134           1 :             aosReport.push_back(
     135             :                 "Reference file and input file differ at the binary level.");
     136           1 :             return false;
     137             :         }
     138           4 :     } while (fpRef->Tell() < nRefSize);
     139             : 
     140           4 :     return true;
     141             : }
     142             : 
     143             : //! @endcond

Generated by: LCOV version 1.14