Line data Source code
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 773 : ZarrV3CodecCRC32C::ZarrV3CodecCRC32C() : ZarrV3Codec(NAME) 24 : { 25 773 : } 26 : 27 : /************************************************************************/ 28 : /* ZarrV3CodecCRC32C::Clone() */ 29 : /************************************************************************/ 30 : 31 0 : std::unique_ptr<ZarrV3Codec> ZarrV3CodecCRC32C::Clone() const 32 : { 33 0 : auto psClone = std::make_unique<ZarrV3CodecCRC32C>(); 34 0 : ZarrArrayMetadata oOutputArrayMetadata; 35 0 : psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata, 36 : oOutputArrayMetadata, 37 : /* bEmitWarnings = */ false); 38 0 : return psClone; 39 : } 40 : 41 : /************************************************************************/ 42 : /* ZarrV3CodecCRC32C::InitFromConfiguration() */ 43 : /************************************************************************/ 44 : 45 773 : bool ZarrV3CodecCRC32C::InitFromConfiguration( 46 : const CPLJSONObject &configuration, 47 : const ZarrArrayMetadata &oInputArrayMetadata, 48 : ZarrArrayMetadata &oOutputArrayMetadata, bool /* bEmitWarnings */) 49 : { 50 773 : m_oConfiguration = configuration.Clone(); 51 773 : m_oInputArrayMetadata = oInputArrayMetadata; 52 773 : oOutputArrayMetadata = oInputArrayMetadata; 53 : 54 : // GDAL extension for tests !!! 55 773 : if (!m_oConfiguration.GetBool("check_crc", true)) 56 135 : m_bCheckCRC = false; 57 : 58 773 : return true; 59 : } 60 : 61 : /************************************************************************/ 62 : /* ComputeCRC32C() */ 63 : /************************************************************************/ 64 : 65 168 : static uint32_t ComputeCRC32C(const GByte *pabyIn, size_t nLength) 66 : { 67 168 : crc32c_init(); 68 168 : return crc32c(0, pabyIn, nLength); 69 : } 70 : 71 : /************************************************************************/ 72 : /* ZarrV3CodecCRC32C::Encode() */ 73 : /************************************************************************/ 74 : 75 0 : bool ZarrV3CodecCRC32C::Encode(const ZarrByteVectorQuickResize &abySrc, 76 : ZarrByteVectorQuickResize &abyDst) const 77 : { 78 0 : abyDst.clear(); 79 0 : abyDst.insert(abyDst.end(), abySrc.begin(), abySrc.end()); 80 : 81 : 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 : } 88 : 89 : /************************************************************************/ 90 : /* ZarrV3CodecCRC32C::Decode() */ 91 : /************************************************************************/ 92 : 93 303 : bool ZarrV3CodecCRC32C::Decode(const ZarrByteVectorQuickResize &abySrc, 94 : ZarrByteVectorQuickResize &abyDst) const 95 : { 96 303 : if (abySrc.size() < sizeof(uint32_t)) 97 : { 98 0 : CPLError(CE_Failure, CPLE_AppDefined, 99 : "CRC32C decoder: not enough input bytes"); 100 0 : return false; 101 : } 102 : 103 303 : const size_t nSrcLen = abySrc.size() - sizeof(uint32_t); 104 303 : abyDst.clear(); 105 303 : abyDst.insert(abyDst.end(), abySrc.begin(), abySrc.begin() + nSrcLen); 106 : 107 303 : if (m_bCheckCRC) 108 : { 109 : const uint32_t nComputedCRC = 110 168 : ComputeCRC32C(abyDst.data(), abyDst.size()); 111 168 : const uint32_t nExpectedCRC = CPL_LSBUINT32PTR(abySrc.data() + nSrcLen); 112 168 : if (nComputedCRC != nExpectedCRC) 113 : { 114 51 : CPLError( 115 : CE_Failure, CPLE_AppDefined, 116 : "CRC32C decoder: computed CRC value is %08X whereas expected " 117 : "value is %08X", 118 : nComputedCRC, nExpectedCRC); 119 51 : return false; 120 : } 121 : } 122 : 123 252 : return true; 124 : }