/src/gdal/frmts/zarr/zarr_v3_codec_crc32c.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL |
4 | | * Purpose: Zarr driver, "crc32c" codec |
5 | | * Author: Even Rouault <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2026, Development Seed |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "zarr_v3_codec.h" |
14 | | |
15 | | #include "crc32c.h" |
16 | | |
17 | | // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/crc32c/index.html |
18 | | |
19 | | /************************************************************************/ |
20 | | /* ZarrV3CodecCRC32C::ZarrV3CodecCRC32C() */ |
21 | | /************************************************************************/ |
22 | | |
23 | 0 | ZarrV3CodecCRC32C::ZarrV3CodecCRC32C() : ZarrV3Codec(NAME) |
24 | 0 | { |
25 | 0 | } |
26 | | |
27 | | /************************************************************************/ |
28 | | /* ZarrV3CodecCRC32C::Clone() */ |
29 | | /************************************************************************/ |
30 | | |
31 | | std::unique_ptr<ZarrV3Codec> ZarrV3CodecCRC32C::Clone() const |
32 | 0 | { |
33 | 0 | auto psClone = std::make_unique<ZarrV3CodecCRC32C>(); |
34 | 0 | ZarrArrayMetadata oOutputArrayMetadata; |
35 | 0 | psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata, |
36 | 0 | oOutputArrayMetadata, |
37 | 0 | /* bEmitWarnings = */ false); |
38 | 0 | return psClone; |
39 | 0 | } |
40 | | |
41 | | /************************************************************************/ |
42 | | /* ZarrV3CodecCRC32C::InitFromConfiguration() */ |
43 | | /************************************************************************/ |
44 | | |
45 | | bool ZarrV3CodecCRC32C::InitFromConfiguration( |
46 | | const CPLJSONObject &configuration, |
47 | | const ZarrArrayMetadata &oInputArrayMetadata, |
48 | | ZarrArrayMetadata &oOutputArrayMetadata, bool /* bEmitWarnings */) |
49 | 0 | { |
50 | 0 | m_oConfiguration = configuration.Clone(); |
51 | 0 | m_oInputArrayMetadata = oInputArrayMetadata; |
52 | 0 | oOutputArrayMetadata = oInputArrayMetadata; |
53 | | |
54 | | // GDAL extension for tests !!! |
55 | 0 | if (!m_oConfiguration.GetBool("check_crc", true)) |
56 | 0 | m_bCheckCRC = false; |
57 | |
|
58 | 0 | return true; |
59 | 0 | } |
60 | | |
61 | | /************************************************************************/ |
62 | | /* ComputeCRC32C() */ |
63 | | /************************************************************************/ |
64 | | |
65 | | static uint32_t ComputeCRC32C(const GByte *pabyIn, size_t nLength) |
66 | 0 | { |
67 | 0 | crc32c_init(); |
68 | 0 | return crc32c(0, pabyIn, nLength); |
69 | 0 | } |
70 | | |
71 | | /************************************************************************/ |
72 | | /* ZarrV3CodecCRC32C::Encode() */ |
73 | | /************************************************************************/ |
74 | | |
75 | | bool ZarrV3CodecCRC32C::Encode(const ZarrByteVectorQuickResize &abySrc, |
76 | | ZarrByteVectorQuickResize &abyDst) const |
77 | 0 | { |
78 | 0 | abyDst.clear(); |
79 | 0 | abyDst.insert(abyDst.end(), abySrc.begin(), abySrc.end()); |
80 | |
|
81 | 0 | const uint32_t nComputedCRC_le = |
82 | 0 | CPL_LSBWORD32(ComputeCRC32C(abySrc.data(), abySrc.size())); |
83 | 0 | const GByte *pabyCRC = reinterpret_cast<const GByte *>(&nComputedCRC_le); |
84 | 0 | abyDst.insert(abyDst.end(), pabyCRC, pabyCRC + sizeof(uint32_t)); |
85 | |
|
86 | 0 | return true; |
87 | 0 | } |
88 | | |
89 | | /************************************************************************/ |
90 | | /* ZarrV3CodecCRC32C::Decode() */ |
91 | | /************************************************************************/ |
92 | | |
93 | | bool ZarrV3CodecCRC32C::Decode(const ZarrByteVectorQuickResize &abySrc, |
94 | | ZarrByteVectorQuickResize &abyDst) const |
95 | 0 | { |
96 | 0 | if (abySrc.size() < sizeof(uint32_t)) |
97 | 0 | { |
98 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
99 | 0 | "CRC32C decoder: not enough input bytes"); |
100 | 0 | return false; |
101 | 0 | } |
102 | | |
103 | 0 | const size_t nSrcLen = abySrc.size() - sizeof(uint32_t); |
104 | 0 | abyDst.clear(); |
105 | 0 | abyDst.insert(abyDst.end(), abySrc.begin(), abySrc.begin() + nSrcLen); |
106 | |
|
107 | 0 | if (m_bCheckCRC) |
108 | 0 | { |
109 | 0 | const uint32_t nComputedCRC = |
110 | 0 | ComputeCRC32C(abyDst.data(), abyDst.size()); |
111 | 0 | const uint32_t nExpectedCRC = CPL_LSBUINT32PTR(abySrc.data() + nSrcLen); |
112 | 0 | if (nComputedCRC != nExpectedCRC) |
113 | 0 | { |
114 | 0 | CPLError( |
115 | 0 | CE_Failure, CPLE_AppDefined, |
116 | 0 | "CRC32C decoder: computed CRC value is %08X whereas expected " |
117 | 0 | "value is %08X", |
118 | 0 | nComputedCRC, nExpectedCRC); |
119 | 0 | return false; |
120 | 0 | } |
121 | 0 | } |
122 | | |
123 | 0 | return true; |
124 | 0 | } |