Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: Zarr driver, "bytes" 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 : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/bytes/index.html 16 : 17 : /************************************************************************/ 18 : /* ZarrV3CodecBytes() */ 19 : /************************************************************************/ 20 : 21 1975 : ZarrV3CodecBytes::ZarrV3CodecBytes() : ZarrV3Codec(NAME) 22 : { 23 1975 : } 24 : 25 : /************************************************************************/ 26 : /* GetConfiguration() */ 27 : /************************************************************************/ 28 : 29 203 : /* static */ CPLJSONObject ZarrV3CodecBytes::GetConfiguration(bool bLittle) 30 : { 31 203 : CPLJSONObject oConfig; 32 203 : oConfig.Add("endian", bLittle ? "little" : "big"); 33 203 : return oConfig; 34 : } 35 : 36 : /************************************************************************/ 37 : /* ZarrV3CodecBytes::InitFromConfiguration() */ 38 : /************************************************************************/ 39 : 40 1975 : bool ZarrV3CodecBytes::InitFromConfiguration( 41 : const CPLJSONObject &configuration, 42 : const ZarrArrayMetadata &oInputArrayMetadata, 43 : ZarrArrayMetadata &oOutputArrayMetadata, bool /* bEmitWarnings */) 44 : { 45 1975 : m_oConfiguration = configuration.Clone(); 46 1975 : m_bLittle = true; 47 1975 : m_oInputArrayMetadata = oInputArrayMetadata; 48 1975 : oOutputArrayMetadata = oInputArrayMetadata; 49 : 50 1975 : if (configuration.IsValid()) 51 : { 52 1950 : if (configuration.GetType() != CPLJSONObject::Type::Object) 53 : { 54 0 : CPLError(CE_Failure, CPLE_AppDefined, 55 : "Codec endian: configuration is not an object"); 56 0 : return false; 57 : } 58 : 59 3900 : for (const auto &oChild : configuration.GetChildren()) 60 : { 61 1950 : if (oChild.GetName() != "endian") 62 : { 63 0 : CPLError(CE_Failure, CPLE_AppDefined, 64 : "Codec endian: configuration contains a unhandled " 65 : "member: %s", 66 0 : oChild.GetName().c_str()); 67 0 : return false; 68 : } 69 : } 70 : 71 3900 : const auto oEndian = configuration.GetObj("endian"); 72 1950 : if (oEndian.IsValid()) 73 : { 74 1950 : if (oEndian.GetType() != CPLJSONObject::Type::String) 75 : { 76 0 : CPLError(CE_Failure, CPLE_AppDefined, 77 : "Codec gzip: endian is not a string"); 78 0 : return false; 79 : } 80 1950 : if (oEndian.ToString() == "little") 81 1885 : m_bLittle = true; 82 65 : else if (oEndian.ToString() == "big") 83 65 : m_bLittle = false; 84 : else 85 : { 86 0 : CPLError(CE_Failure, CPLE_AppDefined, 87 : "Codec gzip: invalid value for endian"); 88 0 : return false; 89 : } 90 : } 91 : } 92 : 93 1975 : return true; 94 : } 95 : 96 : /************************************************************************/ 97 : /* ZarrV3CodecBytes::Clone() */ 98 : /************************************************************************/ 99 : 100 0 : std::unique_ptr<ZarrV3Codec> ZarrV3CodecBytes::Clone() const 101 : { 102 0 : auto psClone = std::make_unique<ZarrV3CodecBytes>(); 103 0 : ZarrArrayMetadata oOutputArrayMetadata; 104 0 : psClone->InitFromConfiguration(m_oConfiguration, m_oInputArrayMetadata, 105 : oOutputArrayMetadata, 106 : /* bEmitWarnings = */ false); 107 0 : return psClone; 108 : } 109 : 110 : /************************************************************************/ 111 : /* ZarrV3CodecBytes::Encode() */ 112 : /************************************************************************/ 113 : 114 53 : bool ZarrV3CodecBytes::Encode(const ZarrByteVectorQuickResize &abySrc, 115 : ZarrByteVectorQuickResize &abyDst) const 116 : { 117 53 : CPLAssert(!IsNoOp()); 118 : 119 53 : size_t nEltCount = MultiplyElements(m_oInputArrayMetadata.anBlockSizes); 120 53 : size_t nNativeSize = m_oInputArrayMetadata.oElt.nativeSize; 121 53 : if (abySrc.size() < nEltCount * nNativeSize) 122 : { 123 0 : CPLError(CE_Failure, CPLE_AppDefined, 124 : "ZarrV3CodecBytes::Encode(): input buffer too small"); 125 0 : return false; 126 : } 127 53 : CPLAssert(abySrc.size() >= nEltCount * nNativeSize); 128 53 : abyDst.resize(nEltCount * nNativeSize); 129 : 130 53 : const GByte *pabySrc = abySrc.data(); 131 53 : GByte *pabyDst = abyDst.data(); 132 : 133 53 : if (m_oInputArrayMetadata.oElt.nativeType == 134 : DtypeElt::NativeType::STRING_UNICODE) 135 : { 136 : // Swap each 4-byte UCS-4 character individually 137 0 : const size_t nTotalBytes = nEltCount * nNativeSize; 138 0 : for (size_t i = 0; i < nTotalBytes; i += 4) 139 : { 140 0 : const uint32_t val = 141 0 : CPL_SWAP32(*reinterpret_cast<const uint32_t *>(pabySrc + i)); 142 0 : memcpy(pabyDst + i, &val, sizeof(val)); 143 : } 144 0 : return true; 145 : } 146 53 : if (m_oInputArrayMetadata.oElt.nativeType == 147 : DtypeElt::NativeType::COMPLEX_IEEEFP) 148 : { 149 0 : nEltCount *= 2; 150 0 : nNativeSize /= 2; 151 : } 152 53 : if (nNativeSize == 2) 153 : { 154 36 : for (size_t i = 0; i < nEltCount; ++i) 155 : { 156 24 : const uint16_t val = CPL_SWAP16(*reinterpret_cast<const uint16_t *>( 157 : pabySrc + sizeof(uint16_t) * i)); 158 24 : memcpy(pabyDst + sizeof(uint16_t) * i, &val, sizeof(val)); 159 : } 160 : } 161 41 : else if (nNativeSize == 4) 162 : { 163 54 : for (size_t i = 0; i < nEltCount; ++i) 164 : { 165 36 : const uint32_t val = CPL_SWAP32(*reinterpret_cast<const uint32_t *>( 166 : pabySrc + sizeof(uint32_t) * i)); 167 36 : memcpy(pabyDst + sizeof(uint32_t) * i, &val, sizeof(val)); 168 : } 169 : } 170 23 : else if (nNativeSize == 8) 171 : { 172 75 : for (size_t i = 0; i < nEltCount; ++i) 173 : { 174 52 : const uint64_t val = CPL_SWAP64(*reinterpret_cast<const uint64_t *>( 175 : pabySrc + sizeof(uint64_t) * i)); 176 52 : memcpy(pabyDst + sizeof(uint64_t) * i, &val, sizeof(val)); 177 : } 178 : } 179 : else 180 : { 181 0 : CPLAssert(false); 182 : } 183 53 : return true; 184 : } 185 : 186 : /************************************************************************/ 187 : /* ZarrV3CodecBytes::Decode() */ 188 : /************************************************************************/ 189 : 190 29 : bool ZarrV3CodecBytes::Decode(const ZarrByteVectorQuickResize &abySrc, 191 : ZarrByteVectorQuickResize &abyDst) const 192 : { 193 29 : return Encode(abySrc, abyDst); 194 : }