Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_compare_common.cpp
Line
Count
Source
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
0
GDALCompareCommon::GDALCompareCommon() = default;
23
24
0
GDALCompareCommon::~GDALCompareCommon() = default;
25
26
/************************************************************************/
27
/*            GDALRasterCompareAlgorithm::BinaryComparison()            */
28
/************************************************************************/
29
30
/* static */
31
bool GDALCompareCommon::BinaryComparison(GDALAlgorithm *alg,
32
                                         std::vector<std::string> &aosReport,
33
                                         GDALDataset *poRefDS,
34
                                         GDALDataset *poInputDS)
35
0
{
36
0
    if (poRefDS->GetDescription()[0] == 0)
37
0
    {
38
0
        alg->ReportError(
39
0
            CE_Warning, CPLE_AppDefined,
40
0
            "Reference dataset has no name. Skipping binary file comparison");
41
0
        return false;
42
0
    }
43
44
0
    auto poRefDrv = poRefDS->GetDriver();
45
0
    if (poRefDrv && EQUAL(poRefDrv->GetDescription(), "MEM"))
46
0
    {
47
0
        alg->ReportError(
48
0
            CE_Warning, CPLE_AppDefined,
49
0
            "Reference dataset is a in-memory dataset. Skipping binary "
50
0
            "file comparison");
51
0
        return false;
52
0
    }
53
54
0
    if (poInputDS->GetDescription()[0] == 0)
55
0
    {
56
0
        alg->ReportError(
57
0
            CE_Warning, CPLE_AppDefined,
58
0
            "Input dataset has no name. Skipping binary file comparison");
59
0
        return false;
60
0
    }
61
62
0
    auto poInputDrv = poInputDS->GetDriver();
63
0
    if (poInputDrv && EQUAL(poInputDrv->GetDescription(), "MEM"))
64
0
    {
65
0
        alg->ReportError(
66
0
            CE_Warning, CPLE_AppDefined,
67
0
            "Input dataset is a in-memory dataset. Skipping binary "
68
0
            "file comparison");
69
0
        return false;
70
0
    }
71
72
0
    VSIVirtualHandleUniquePtr fpRef(VSIFOpenL(poRefDS->GetDescription(), "rb"));
73
0
    VSIVirtualHandleUniquePtr fpInput(
74
0
        VSIFOpenL(poInputDS->GetDescription(), "rb"));
75
0
    if (!fpRef)
76
0
    {
77
0
        alg->ReportError(
78
0
            CE_Warning, CPLE_AppDefined,
79
0
            "Reference dataset '%s' is not a file. Skipping binary "
80
0
            "file comparison",
81
0
            poRefDS->GetDescription());
82
0
        return false;
83
0
    }
84
85
0
    if (!fpInput)
86
0
    {
87
0
        alg->ReportError(
88
0
            CE_Warning, CPLE_AppDefined,
89
0
            "Input dataset '%s' is not a file. Skipping binary file comparison",
90
0
            poInputDS->GetDescription());
91
0
        return false;
92
0
    }
93
94
0
    fpRef->Seek(0, SEEK_END);
95
0
    fpInput->Seek(0, SEEK_END);
96
0
    const auto nRefSize = fpRef->Tell();
97
0
    const auto nInputSize = fpInput->Tell();
98
0
    if (nRefSize != nInputSize)
99
0
    {
100
0
        aosReport.push_back("Reference file has size " +
101
0
                            std::to_string(nRefSize) +
102
0
                            " bytes, whereas input file has size " +
103
0
                            std::to_string(nInputSize) + " bytes.");
104
105
0
        return false;
106
0
    }
107
108
0
    constexpr size_t BUF_SIZE = 1024 * 1024;
109
0
    std::vector<GByte> abyRef(BUF_SIZE);
110
0
    std::vector<GByte> abyInput(BUF_SIZE);
111
112
0
    fpRef->Seek(0, SEEK_SET);
113
0
    fpInput->Seek(0, SEEK_SET);
114
115
0
    do
116
0
    {
117
0
        const size_t nRefRead = fpRef->Read(abyRef.data(), 1, BUF_SIZE);
118
0
        const size_t nInputRead = fpInput->Read(abyInput.data(), 1, BUF_SIZE);
119
120
0
        if (nRefRead != BUF_SIZE && fpRef->Tell() != nRefSize)
121
0
        {
122
0
            aosReport.push_back("Failed to fully read reference file");
123
0
            return false;
124
0
        }
125
126
0
        if (nInputRead != BUF_SIZE && fpInput->Tell() != nRefSize)
127
0
        {
128
0
            aosReport.push_back("Failed to fully read input file");
129
0
            return false;
130
0
        }
131
132
0
        if (abyRef != abyInput)
133
0
        {
134
0
            aosReport.push_back(
135
0
                "Reference file and input file differ at the binary level.");
136
0
            return false;
137
0
        }
138
0
    } while (fpRef->Tell() < nRefSize);
139
140
0
    return true;
141
0
}
142
143
//! @endcond