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