Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/zarr/zarr_v3_codec_blosc.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  Zarr driver, "blosc" codec
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "zarr_v3_codec.h"
14
15
#include "cpl_compressor.h"
16
17
// Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/blosc/index.html
18
19
/************************************************************************/
20
/*                          ZarrV3CodecBlosc()                          */
21
/************************************************************************/
22
23
0
ZarrV3CodecBlosc::ZarrV3CodecBlosc() : ZarrV3CodecAbstractCompressor(NAME)
24
0
{
25
0
}
26
27
/************************************************************************/
28
/*                          GetConfiguration()                          */
29
/************************************************************************/
30
31
/* static */ CPLJSONObject
32
ZarrV3CodecBlosc::GetConfiguration(const char *cname, int clevel,
33
                                   const char *shuffle, int typesize,
34
                                   int blocksize)
35
0
{
36
0
    CPLJSONObject oConfig;
37
0
    oConfig.Add("cname", cname);
38
0
    oConfig.Add("clevel", clevel);
39
0
    oConfig.Add("shuffle", shuffle);
40
0
    if (strcmp(shuffle, "noshuffle") != 0)
41
0
        oConfig.Add("typesize", typesize);
42
0
    oConfig.Add("blocksize", blocksize);
43
0
    return oConfig;
44
0
}
45
46
/************************************************************************/
47
/*              ZarrV3CodecBlosc::InitFromConfiguration()               */
48
/************************************************************************/
49
50
bool ZarrV3CodecBlosc::InitFromConfiguration(
51
    const CPLJSONObject &configuration,
52
    const ZarrArrayMetadata &oInputArrayMetadata,
53
    ZarrArrayMetadata &oOutputArrayMetadata, bool /* bEmitWarnings */)
54
0
{
55
0
    m_pCompressor = CPLGetCompressor("blosc");
56
0
    m_pDecompressor = CPLGetDecompressor("blosc");
57
0
    if (!m_pCompressor || !m_pDecompressor)
58
0
    {
59
0
        CPLError(CE_Failure, CPLE_AppDefined, "blosc compressor not available");
60
0
        return false;
61
0
    }
62
63
0
    m_oConfiguration = configuration.Clone();
64
0
    m_oInputArrayMetadata = oInputArrayMetadata;
65
    // byte->byte codec
66
0
    oOutputArrayMetadata = oInputArrayMetadata;
67
68
0
    if (!configuration.IsValid() ||
69
0
        configuration.GetType() != CPLJSONObject::Type::Object)
70
0
    {
71
0
        CPLError(CE_Failure, CPLE_AppDefined,
72
0
                 "Codec blosc: configuration missing or not an object");
73
0
        return false;
74
0
    }
75
76
0
    for (const auto &oChild : configuration.GetChildren())
77
0
    {
78
0
        const auto osName = oChild.GetName();
79
0
        if (osName != "cname" && osName != "clevel" && osName != "shuffle" &&
80
0
            osName != "typesize" && osName != "blocksize")
81
0
        {
82
0
            CPLError(
83
0
                CE_Failure, CPLE_AppDefined,
84
0
                "Codec blosc: configuration contains a unhandled member: %s",
85
0
                osName.c_str());
86
0
            return false;
87
0
        }
88
0
    }
89
90
0
    const auto oCname = configuration.GetObj("cname");
91
0
    if (oCname.GetType() != CPLJSONObject::Type::String)
92
0
    {
93
0
        CPLError(CE_Failure, CPLE_AppDefined,
94
0
                 "Codec blosc: cname is missing or not a string");
95
0
        return false;
96
0
    }
97
0
    m_aosCompressorOptions.SetNameValue("CNAME", oCname.ToString().c_str());
98
99
0
    const auto oLevel = configuration.GetObj("clevel");
100
0
    if (oLevel.IsValid())
101
0
    {
102
0
        if (oLevel.GetType() != CPLJSONObject::Type::Integer)
103
0
        {
104
0
            CPLError(CE_Failure, CPLE_AppDefined,
105
0
                     "Codec blosc: clevel is not an integer");
106
0
            return false;
107
0
        }
108
0
        const int nLevel = oLevel.ToInteger();
109
0
        if (nLevel < 0 || nLevel > 9)
110
0
        {
111
0
            CPLError(CE_Failure, CPLE_AppDefined,
112
0
                     "Codec blosc: invalid clevel value for level: %d", nLevel);
113
0
            return false;
114
0
        }
115
0
        m_aosCompressorOptions.SetNameValue("CLEVEL", CPLSPrintf("%d", nLevel));
116
0
    }
117
118
0
    const auto oShuffle = configuration.GetObj("shuffle");
119
0
    if (oShuffle.GetType() != CPLJSONObject::Type::String)
120
0
    {
121
0
        CPLError(CE_Failure, CPLE_AppDefined,
122
0
                 "Codec blosc: shuffle is missing or not a string");
123
0
        return false;
124
0
    }
125
0
    if (oShuffle.ToString() == "noshuffle")
126
0
        m_aosCompressorOptions.SetNameValue("SHUFFLE", "NONE");
127
0
    else if (oShuffle.ToString() == "shuffle")
128
0
        m_aosCompressorOptions.SetNameValue("SHUFFLE", "BYTE");
129
0
    else if (oShuffle.ToString() == "bitshuffle")
130
0
        m_aosCompressorOptions.SetNameValue("SHUFFLE", "BIT");
131
0
    else
132
0
    {
133
0
        CPLError(CE_Failure, CPLE_AppDefined,
134
0
                 "Codec blosc: Invalid value for shuffle");
135
0
        return false;
136
0
    }
137
138
0
    const auto oTypesize = configuration.GetObj("typesize");
139
0
    if (oTypesize.IsValid())
140
0
    {
141
0
        if (oTypesize.GetType() != CPLJSONObject::Type::Integer)
142
0
        {
143
0
            CPLError(CE_Failure, CPLE_AppDefined,
144
0
                     "Codec blosc: typesize is not an integer");
145
0
            return false;
146
0
        }
147
0
        const int nTypeSize = oTypesize.ToInteger();
148
0
        m_aosCompressorOptions.SetNameValue("TYPESIZE",
149
0
                                            CPLSPrintf("%d", nTypeSize));
150
0
    }
151
152
0
    const auto oBlocksize = configuration.GetObj("blocksize");
153
0
    if (oBlocksize.IsValid())
154
0
    {
155
0
        if (oBlocksize.GetType() != CPLJSONObject::Type::Integer)
156
0
        {
157
0
            CPLError(CE_Failure, CPLE_AppDefined,
158
0
                     "Codec blosc: blocksize is not an integer");
159
0
            return false;
160
0
        }
161
0
        const int nBlocksize = oBlocksize.ToInteger();
162
0
        m_aosCompressorOptions.SetNameValue("BLOCKSIZE",
163
0
                                            CPLSPrintf("%d", nBlocksize));
164
0
    }
165
166
0
    return true;
167
0
}
168
169
/************************************************************************/
170
/*                      ZarrV3CodecBlosc::Clone()                       */
171
/************************************************************************/
172
173
std::unique_ptr<ZarrV3Codec> ZarrV3CodecBlosc::Clone() const
174
0
{
175
0
    auto psClone = std::make_unique<ZarrV3CodecBlosc>();
176
0
    ZarrArrayMetadata oOutputArrayMetadata;
177
0
    psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata,
178
0
                                   oOutputArrayMetadata,
179
0
                                   /* bEmitWarnings = */ false);
180
0
    return psClone;
181
0
}