Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Zarr driver
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #ifndef ZARR_H
14 : #define ZARR_H
15 :
16 : #include "cpl_compressor.h"
17 : #include "cpl_json.h"
18 : #include "gdal_priv.h"
19 : #include "gdal_pam.h"
20 : #include "memmultidim.h"
21 :
22 : #include <array>
23 : #include <map>
24 : #include <memory>
25 : #include <mutex>
26 : #include <set>
27 :
28 : #define ZARR_DEBUG_KEY "ZARR"
29 :
30 : #define CRS_ATTRIBUTE_NAME "_CRS"
31 :
32 : const CPLCompressor *ZarrGetShuffleCompressor();
33 : const CPLCompressor *ZarrGetShuffleDecompressor();
34 : const CPLCompressor *ZarrGetQuantizeDecompressor();
35 :
36 : /************************************************************************/
37 : /* ZarrDataset */
38 : /************************************************************************/
39 :
40 : class ZarrDataset final : public GDALDataset
41 : {
42 : friend class ZarrRasterBand;
43 :
44 : std::shared_ptr<GDALGroup> m_poRootGroup{};
45 : CPLStringList m_aosSubdatasets{};
46 : std::array<double, 6> m_adfGeoTransform{{0.0, 1.0, 0.0, 0.0, 0.0, 1.0}};
47 : bool m_bHasGT = false;
48 : std::shared_ptr<GDALDimension> m_poDimX{};
49 : std::shared_ptr<GDALDimension> m_poDimY{};
50 : std::shared_ptr<GDALMDArray> m_poSingleArray{};
51 :
52 : static GDALDataset *OpenMultidim(const char *pszFilename, bool bUpdateMode,
53 : CSLConstList papszOpenOptions);
54 :
55 : public:
56 : explicit ZarrDataset(const std::shared_ptr<GDALGroup> &poRootGroup);
57 : ~ZarrDataset() override;
58 :
59 : CPLErr FlushCache(bool bAtClosing = false) override;
60 :
61 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
62 : static GDALDataset *
63 : CreateMultiDimensional(const char *pszFilename,
64 : CSLConstList /*papszRootGroupOptions*/,
65 : CSLConstList /*papszOptions*/);
66 :
67 : static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
68 : int nBands, GDALDataType eType,
69 : char **papszOptions);
70 :
71 : const char *GetMetadataItem(const char *pszName,
72 : const char *pszDomain) override;
73 : char **GetMetadata(const char *pszDomain) override;
74 :
75 : CPLErr SetMetadata(char **papszMetadata, const char *pszDomain) override;
76 :
77 : const OGRSpatialReference *GetSpatialRef() const override;
78 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
79 :
80 : CPLErr GetGeoTransform(double *padfTransform) override;
81 : CPLErr SetGeoTransform(double *padfTransform) override;
82 :
83 856 : std::shared_ptr<GDALGroup> GetRootGroup() const override
84 : {
85 856 : return m_poRootGroup;
86 : }
87 : };
88 :
89 : /************************************************************************/
90 : /* ZarrRasterBand */
91 : /************************************************************************/
92 :
93 : class ZarrRasterBand final : public GDALRasterBand
94 : {
95 : friend class ZarrDataset;
96 :
97 : std::shared_ptr<GDALMDArray> m_poArray;
98 : GDALColorInterp m_eColorInterp = GCI_Undefined;
99 :
100 : protected:
101 : CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
102 : CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
103 : CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
104 : int nYSize, void *pData, int nBufXSize, int nBufYSize,
105 : GDALDataType eBufType, GSpacing nPixelSpaceBuf,
106 : GSpacing nLineSpaceBuf,
107 : GDALRasterIOExtraArg *psExtraArg) override;
108 :
109 : public:
110 : explicit ZarrRasterBand(const std::shared_ptr<GDALMDArray> &poArray);
111 :
112 : double GetNoDataValue(int *pbHasNoData) override;
113 : int64_t GetNoDataValueAsInt64(int *pbHasNoData) override;
114 : uint64_t GetNoDataValueAsUInt64(int *pbHasNoData) override;
115 : CPLErr SetNoDataValue(double dfNoData) override;
116 : CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
117 : CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
118 : double GetOffset(int *pbSuccess = nullptr) override;
119 : CPLErr SetOffset(double dfNewOffset) override;
120 : double GetScale(int *pbSuccess = nullptr) override;
121 : CPLErr SetScale(double dfNewScale) override;
122 : const char *GetUnitType() override;
123 : CPLErr SetUnitType(const char *pszNewValue) override;
124 : GDALColorInterp GetColorInterpretation() override;
125 : CPLErr SetColorInterpretation(GDALColorInterp eColorInterp) override;
126 : };
127 :
128 : /************************************************************************/
129 : /* ZarrAttributeGroup() */
130 : /************************************************************************/
131 :
132 : class ZarrAttributeGroup
133 : {
134 : // Use a MEMGroup as a convenient container for attributes.
135 : const bool m_bContainerIsGroup;
136 : std::shared_ptr<MEMGroup> m_poGroup;
137 : bool m_bModified = false;
138 :
139 : public:
140 : explicit ZarrAttributeGroup(const std::string &osParentName,
141 : bool bContainerIsGroup);
142 :
143 : void Init(const CPLJSONObject &obj, bool bUpdatable);
144 :
145 129 : std::shared_ptr<GDALAttribute> GetAttribute(const std::string &osName) const
146 : {
147 129 : return m_poGroup->GetAttribute(osName);
148 : }
149 :
150 : std::vector<std::shared_ptr<GDALAttribute>>
151 159 : GetAttributes(CSLConstList papszOptions = nullptr) const
152 : {
153 159 : return m_poGroup->GetAttributes(papszOptions);
154 : }
155 :
156 : std::shared_ptr<GDALAttribute>
157 175 : CreateAttribute(const std::string &osName,
158 : const std::vector<GUInt64> &anDimensions,
159 : const GDALExtendedDataType &oDataType,
160 : CSLConstList /* papszOptions */ = nullptr)
161 : {
162 175 : auto poAttr = m_poGroup->CreateAttribute(osName, anDimensions,
163 175 : oDataType, nullptr);
164 175 : if (poAttr)
165 : {
166 175 : m_bModified = true;
167 : }
168 175 : return poAttr;
169 : }
170 :
171 24 : bool DeleteAttribute(const std::string &osName)
172 : {
173 24 : const bool bOK = m_poGroup->DeleteAttribute(osName, nullptr);
174 24 : if (bOK)
175 : {
176 12 : m_bModified = true;
177 : }
178 24 : return bOK;
179 : }
180 :
181 805 : void SetUpdatable(bool bUpdatable)
182 : {
183 1610 : auto attrs = m_poGroup->GetAttributes(nullptr);
184 1151 : for (auto &attr : attrs)
185 : {
186 692 : auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
187 346 : if (memAttr)
188 346 : memAttr->SetWritable(bUpdatable);
189 : }
190 805 : }
191 :
192 410 : void UnsetModified()
193 : {
194 410 : m_bModified = false;
195 820 : auto attrs = m_poGroup->GetAttributes(nullptr);
196 535 : for (auto &attr : attrs)
197 : {
198 250 : auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
199 125 : if (memAttr)
200 125 : memAttr->SetModified(false);
201 : }
202 410 : }
203 :
204 4256 : bool IsModified() const
205 : {
206 4256 : if (m_bModified)
207 114 : return true;
208 8284 : const auto attrs = m_poGroup->GetAttributes(nullptr);
209 4675 : for (const auto &attr : attrs)
210 : {
211 550 : const auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
212 550 : if (memAttr && memAttr->IsModified())
213 17 : return true;
214 : }
215 4125 : return false;
216 : }
217 :
218 : CPLJSONObject Serialize() const;
219 :
220 : void ParentRenamed(const std::string &osNewParentFullName);
221 :
222 : void ParentDeleted();
223 : };
224 :
225 : /************************************************************************/
226 : /* ZarrSharedResource */
227 : /************************************************************************/
228 :
229 : class ZarrGroupBase;
230 :
231 : class ZarrSharedResource
232 : : public std::enable_shared_from_this<ZarrSharedResource>
233 : {
234 : bool m_bUpdatable = false;
235 : std::string m_osRootDirectoryName{};
236 : bool m_bZMetadataEnabled = false;
237 : CPLJSONObject m_oObj{}; // For .zmetadata
238 : bool m_bZMetadataModified = false;
239 : std::shared_ptr<GDALPamMultiDim> m_poPAM{};
240 : CPLStringList m_aosOpenOptions{};
241 : std::weak_ptr<ZarrGroupBase> m_poWeakRootGroup{};
242 : std::set<std::string> m_oSetArrayInLoading{};
243 :
244 : explicit ZarrSharedResource(const std::string &osRootDirectoryName,
245 : bool bUpdatable);
246 :
247 : std::shared_ptr<ZarrGroupBase> OpenRootGroup();
248 :
249 : public:
250 : static std::shared_ptr<ZarrSharedResource>
251 : Create(const std::string &osRootDirectoryName, bool bUpdatable);
252 :
253 : ~ZarrSharedResource();
254 :
255 2277 : bool IsUpdatable() const
256 : {
257 2277 : return m_bUpdatable;
258 : }
259 :
260 167 : void EnableZMetadata()
261 : {
262 167 : m_bZMetadataEnabled = true;
263 167 : }
264 :
265 : void SetZMetadataItem(const std::string &osFilename,
266 : const CPLJSONObject &obj);
267 :
268 : void DeleteZMetadataItemRecursive(const std::string &osFilename);
269 :
270 : void RenameZMetadataRecursive(const std::string &osOldFilename,
271 : const std::string &osNewFilename);
272 :
273 1197 : const std::shared_ptr<GDALPamMultiDim> &GetPAM()
274 : {
275 1197 : return m_poPAM;
276 : }
277 :
278 1210 : const CPLStringList &GetOpenOptions() const
279 : {
280 1210 : return m_aosOpenOptions;
281 : }
282 :
283 696 : void SetOpenOptions(CSLConstList papszOpenOptions)
284 : {
285 696 : m_aosOpenOptions = papszOpenOptions;
286 696 : }
287 :
288 : void
289 : UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poUpdatedDim);
290 :
291 696 : std::shared_ptr<ZarrGroupBase> GetRootGroup()
292 : {
293 696 : auto poRootGroup = m_poWeakRootGroup.lock();
294 696 : if (poRootGroup)
295 0 : return poRootGroup;
296 696 : poRootGroup = OpenRootGroup();
297 696 : m_poWeakRootGroup = poRootGroup;
298 696 : return poRootGroup;
299 : }
300 :
301 80 : void SetRootGroup(const std::shared_ptr<ZarrGroupBase> &poRootGroup)
302 : {
303 80 : m_poWeakRootGroup = poRootGroup;
304 80 : }
305 :
306 : bool AddArrayInLoading(const std::string &osZarrayFilename);
307 : void RemoveArrayInLoading(const std::string &osZarrayFilename);
308 :
309 : struct SetFilenameAdder
310 : {
311 : std::shared_ptr<ZarrSharedResource> m_poSharedResource;
312 : const std::string m_osFilename;
313 : const bool m_bOK;
314 :
315 842 : SetFilenameAdder(
316 : const std::shared_ptr<ZarrSharedResource> &poSharedResource,
317 : const std::string &osFilename)
318 842 : : m_poSharedResource(poSharedResource), m_osFilename(osFilename),
319 842 : m_bOK(m_poSharedResource->AddArrayInLoading(m_osFilename))
320 : {
321 842 : }
322 :
323 842 : ~SetFilenameAdder()
324 842 : {
325 842 : if (m_bOK)
326 840 : m_poSharedResource->RemoveArrayInLoading(m_osFilename);
327 842 : }
328 :
329 842 : bool ok() const
330 : {
331 842 : return m_bOK;
332 : }
333 : };
334 : };
335 :
336 : /************************************************************************/
337 : /* ZarrGroup */
338 : /************************************************************************/
339 :
340 : class ZarrArray;
341 : class ZarrDimension;
342 :
343 : class ZarrGroupBase CPL_NON_FINAL : public GDALGroup
344 : {
345 : protected:
346 : friend class ZarrV2Group;
347 : friend class ZarrV3Group;
348 :
349 : // For ZarrV2, this is the directory of the group
350 : // For ZarrV3, this is the root directory of the dataset
351 : std::shared_ptr<ZarrSharedResource> m_poSharedResource;
352 : std::string m_osDirectoryName{};
353 : std::weak_ptr<ZarrGroupBase>
354 : m_poParent{}; // weak reference to owning parent
355 : std::shared_ptr<ZarrGroupBase>
356 : m_poParentStrongRef{}; // strong reference, used only when opening from
357 : // a subgroup
358 : mutable std::map<CPLString, std::shared_ptr<ZarrGroupBase>> m_oMapGroups{};
359 : mutable std::map<CPLString, std::shared_ptr<ZarrArray>> m_oMapMDArrays{};
360 : mutable std::map<CPLString, std::shared_ptr<ZarrDimension>>
361 : m_oMapDimensions{};
362 : mutable bool m_bDirectoryExplored = false;
363 : mutable std::vector<std::string> m_aosGroups{};
364 : mutable std::vector<std::string> m_aosArrays{};
365 : mutable ZarrAttributeGroup m_oAttrGroup;
366 : mutable bool m_bAttributesLoaded = false;
367 : bool m_bReadFromZMetadata = false;
368 : mutable bool m_bDimensionsInstantiated = false;
369 : bool m_bUpdatable = false;
370 : bool m_bDimSizeInUpdate = false;
371 :
372 : virtual void ExploreDirectory() const = 0;
373 : virtual void LoadAttributes() const = 0;
374 :
375 1461 : ZarrGroupBase(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
376 : const std::string &osParentName, const std::string &osName)
377 1461 : : GDALGroup(osParentName, osName), m_poSharedResource(poSharedResource),
378 1461 : m_oAttrGroup(m_osFullName, /*bContainerIsGroup=*/true)
379 : {
380 1461 : }
381 :
382 : protected:
383 : friend class ZarrDimension;
384 : bool RenameDimension(const std::string &osOldName,
385 : const std::string &osNewName);
386 :
387 : void NotifyChildrenOfRenaming() override;
388 :
389 : void NotifyChildrenOfDeletion() override;
390 :
391 : public:
392 : ~ZarrGroupBase() override;
393 :
394 : std::shared_ptr<GDALAttribute>
395 65 : GetAttribute(const std::string &osName) const override
396 : {
397 65 : LoadAttributes();
398 65 : return m_oAttrGroup.GetAttribute(osName);
399 : }
400 :
401 : std::vector<std::shared_ptr<GDALAttribute>>
402 42 : GetAttributes(CSLConstList papszOptions = nullptr) const override
403 : {
404 42 : LoadAttributes();
405 42 : return m_oAttrGroup.GetAttributes(papszOptions);
406 : }
407 :
408 : std::shared_ptr<GDALAttribute>
409 : CreateAttribute(const std::string &osName,
410 : const std::vector<GUInt64> &anDimensions,
411 : const GDALExtendedDataType &oDataType,
412 : CSLConstList papszOptions = nullptr) override;
413 :
414 : bool DeleteAttribute(const std::string &osName,
415 : CSLConstList papszOptions = nullptr) override;
416 :
417 : std::vector<std::shared_ptr<GDALDimension>>
418 : GetDimensions(CSLConstList papszOptions = nullptr) const override;
419 :
420 : std::shared_ptr<GDALDimension>
421 : CreateDimension(const std::string &osName, const std::string &osType,
422 : const std::string &osDirection, GUInt64 nSize,
423 : CSLConstList papszOptions = nullptr) override;
424 :
425 : std::vector<std::string>
426 : GetMDArrayNames(CSLConstList papszOptions = nullptr) const override;
427 :
428 : std::vector<std::string>
429 : GetGroupNames(CSLConstList papszOptions = nullptr) const override;
430 :
431 : virtual std::shared_ptr<ZarrGroupBase>
432 : OpenZarrGroup(const std::string &osName,
433 : CSLConstList papszOptions = nullptr) const = 0;
434 :
435 : std::shared_ptr<GDALGroup>
436 603 : OpenGroup(const std::string &osName,
437 : CSLConstList papszOptions = nullptr) const override
438 : {
439 : return std::static_pointer_cast<GDALGroup>(
440 603 : OpenZarrGroup(osName, papszOptions));
441 : }
442 :
443 : bool DeleteGroup(const std::string &osName,
444 : CSLConstList papszOptions = nullptr) override;
445 :
446 : std::shared_ptr<GDALMDArray>
447 941 : OpenMDArray(const std::string &osName,
448 : CSLConstList papszOptions = nullptr) const override
449 : {
450 : return std::static_pointer_cast<GDALMDArray>(
451 941 : OpenZarrArray(osName, papszOptions));
452 : }
453 :
454 : bool DeleteMDArray(const std::string &osName,
455 : CSLConstList papszOptions = nullptr) override;
456 :
457 : virtual std::shared_ptr<ZarrArray>
458 : OpenZarrArray(const std::string &osName,
459 : CSLConstList papszOptions = nullptr) const = 0;
460 :
461 1042 : void SetDirectoryName(const std::string &osDirectoryName)
462 : {
463 1042 : m_osDirectoryName = osDirectoryName;
464 1042 : }
465 :
466 9 : const std::string &GetDirectoryName() const
467 : {
468 9 : return m_osDirectoryName;
469 : }
470 :
471 : void RegisterArray(const std::shared_ptr<ZarrArray> &array) const;
472 :
473 1455 : void SetUpdatable(bool bUpdatable)
474 : {
475 1455 : m_bUpdatable = bUpdatable;
476 1455 : }
477 :
478 : void UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poDim);
479 :
480 : static bool IsValidObjectName(const std::string &osName);
481 :
482 : bool Rename(const std::string &osNewName) override;
483 :
484 : //! Returns false in case of error
485 : bool
486 : CheckArrayOrGroupWithSameNameDoesNotExist(const std::string &osName) const;
487 :
488 : void ParentRenamed(const std::string &osNewParentFullName) override;
489 :
490 : void NotifyArrayRenamed(const std::string &osOldName,
491 : const std::string &osNewName);
492 : };
493 :
494 : /************************************************************************/
495 : /* ZarrV2Group */
496 : /************************************************************************/
497 :
498 : class ZarrV2Group final : public ZarrGroupBase
499 : {
500 : void ExploreDirectory() const override;
501 : void LoadAttributes() const override;
502 :
503 : std::shared_ptr<ZarrV2Group>
504 : GetOrCreateSubGroup(const std::string &osSubGroupFullname);
505 :
506 1042 : ZarrV2Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
507 : const std::string &osParentName, const std::string &osName)
508 1042 : : ZarrGroupBase(poSharedResource, osParentName, osName)
509 : {
510 1042 : }
511 :
512 : public:
513 : static std::shared_ptr<ZarrV2Group>
514 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
515 : const std::string &osParentName, const std::string &osName);
516 :
517 : ~ZarrV2Group() override;
518 :
519 : static std::shared_ptr<ZarrV2Group>
520 : CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
521 : const std::string &osParentName, const std::string &osName,
522 : const std::string &osDirectoryName);
523 :
524 : std::shared_ptr<ZarrArray>
525 : OpenZarrArray(const std::string &osName,
526 : CSLConstList papszOptions = nullptr) const override;
527 :
528 : std::shared_ptr<ZarrGroupBase>
529 : OpenZarrGroup(const std::string &osName,
530 : CSLConstList papszOptions = nullptr) const override;
531 :
532 : std::shared_ptr<GDALGroup>
533 : CreateGroup(const std::string &osName,
534 : CSLConstList papszOptions = nullptr) override;
535 :
536 : std::shared_ptr<ZarrArray>
537 : LoadArray(const std::string &osArrayName,
538 : const std::string &osZarrayFilename, const CPLJSONObject &oRoot,
539 : bool bLoadedFromZMetadata,
540 : const CPLJSONObject &oAttributes) const;
541 :
542 : std::shared_ptr<GDALMDArray> CreateMDArray(
543 : const std::string &osName,
544 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
545 : const GDALExtendedDataType &oDataType,
546 : CSLConstList papszOptions = nullptr) override;
547 :
548 : void InitFromZMetadata(const CPLJSONObject &oRoot);
549 : bool InitFromZGroup(const CPLJSONObject &oRoot);
550 : };
551 :
552 : /************************************************************************/
553 : /* ZarrV3Group */
554 : /************************************************************************/
555 :
556 : class ZarrV3Group final : public ZarrGroupBase
557 : {
558 : void ExploreDirectory() const override;
559 : void LoadAttributes() const override;
560 :
561 : ZarrV3Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
562 : const std::string &osParentName, const std::string &osName,
563 : const std::string &osDirectoryName);
564 :
565 : public:
566 : ~ZarrV3Group() override;
567 :
568 : static std::shared_ptr<ZarrV3Group>
569 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
570 : const std::string &osParentName, const std::string &osName,
571 : const std::string &osDirectoryName);
572 :
573 : std::shared_ptr<ZarrArray>
574 : OpenZarrArray(const std::string &osName,
575 : CSLConstList papszOptions = nullptr) const override;
576 :
577 : std::shared_ptr<ZarrGroupBase>
578 : OpenZarrGroup(const std::string &osName,
579 : CSLConstList papszOptions = nullptr) const override;
580 :
581 : static std::shared_ptr<ZarrV3Group>
582 : CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
583 : const std::string &osParentFullName, const std::string &osName,
584 : const std::string &osDirectoryName);
585 :
586 : std::shared_ptr<GDALGroup>
587 : CreateGroup(const std::string &osName,
588 : CSLConstList papszOptions = nullptr) override;
589 :
590 : std::shared_ptr<ZarrArray> LoadArray(const std::string &osArrayName,
591 : const std::string &osZarrayFilename,
592 : const CPLJSONObject &oRoot) const;
593 :
594 : std::shared_ptr<GDALMDArray> CreateMDArray(
595 : const std::string &osName,
596 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
597 : const GDALExtendedDataType &oDataType,
598 : CSLConstList papszOptions = nullptr) override;
599 :
600 53 : void SetExplored()
601 : {
602 53 : m_bDirectoryExplored = true;
603 53 : }
604 : };
605 :
606 : /************************************************************************/
607 : /* ZarrDimension */
608 : /************************************************************************/
609 :
610 : class ZarrDimension final : public GDALDimensionWeakIndexingVar
611 : {
612 : const bool m_bUpdatable;
613 : std::weak_ptr<ZarrGroupBase> m_poParentGroup;
614 : bool m_bModified = false;
615 : bool m_bXArrayDim = false;
616 :
617 : public:
618 2277 : ZarrDimension(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
619 : const std::weak_ptr<ZarrGroupBase> &poParentGroup,
620 : const std::string &osParentName, const std::string &osName,
621 : const std::string &osType, const std::string &osDirection,
622 : GUInt64 nSize)
623 2277 : : GDALDimensionWeakIndexingVar(osParentName, osName, osType,
624 : osDirection, nSize),
625 2277 : m_bUpdatable(poSharedResource->IsUpdatable()),
626 4554 : m_poParentGroup(poParentGroup)
627 : {
628 2277 : }
629 :
630 : bool Rename(const std::string &osNewName) override;
631 :
632 3094 : bool IsModified() const
633 : {
634 3094 : return m_bModified;
635 : }
636 :
637 1024 : void SetXArrayDimension()
638 : {
639 1024 : m_bXArrayDim = true;
640 1024 : }
641 :
642 3857 : bool IsXArrayDimension() const
643 : {
644 3857 : return m_bXArrayDim;
645 : }
646 : };
647 :
648 : /************************************************************************/
649 : /* DtypeElt() */
650 : /************************************************************************/
651 :
652 : struct DtypeElt
653 : {
654 : enum class NativeType
655 : {
656 : BOOLEAN,
657 : UNSIGNED_INT,
658 : SIGNED_INT,
659 : IEEEFP,
660 : COMPLEX_IEEEFP,
661 : STRING_ASCII,
662 : STRING_UNICODE
663 : };
664 :
665 : NativeType nativeType = NativeType::BOOLEAN;
666 : size_t nativeOffset = 0;
667 : size_t nativeSize = 0;
668 : bool needByteSwapping = false;
669 : bool gdalTypeIsApproxOfNative = false;
670 : GDALExtendedDataType gdalType = GDALExtendedDataType::Create(GDT_Unknown);
671 : size_t gdalOffset = 0;
672 : size_t gdalSize = 0;
673 : };
674 :
675 : /************************************************************************/
676 : /* ZarrByteVectorQuickResize */
677 : /************************************************************************/
678 :
679 : /* std::vector<GByte> with quick resizing (ie that doesn't zero out when
680 : * growing back to a previously reached greater size).
681 : */
682 85469 : class ZarrByteVectorQuickResize
683 : {
684 : std::vector<GByte> m_oVec{};
685 : size_t m_nSize = 0;
686 :
687 : public:
688 51702 : ZarrByteVectorQuickResize() = default;
689 :
690 : ZarrByteVectorQuickResize(const ZarrByteVectorQuickResize &) = delete;
691 : ZarrByteVectorQuickResize &
692 : operator=(const ZarrByteVectorQuickResize &) = delete;
693 :
694 31929 : ZarrByteVectorQuickResize(ZarrByteVectorQuickResize &&) = default;
695 : ZarrByteVectorQuickResize &
696 : operator=(ZarrByteVectorQuickResize &&) = default;
697 :
698 101181 : void resize(size_t nNewSize)
699 : {
700 101181 : if (nNewSize > m_oVec.size())
701 32708 : m_oVec.resize(nNewSize);
702 100590 : m_nSize = nNewSize;
703 100590 : }
704 :
705 228059 : inline bool empty() const
706 : {
707 228059 : return m_nSize == 0;
708 : }
709 :
710 159405 : inline size_t size() const
711 : {
712 159405 : return m_nSize;
713 : }
714 :
715 21099 : inline size_t capacity() const
716 : {
717 : // Not a typo: the capacity of this object is the size
718 : // of the underlying std::vector
719 21099 : return m_oVec.size();
720 : }
721 :
722 88883 : inline GByte *data()
723 : {
724 88883 : return m_oVec.data();
725 : }
726 :
727 35883 : inline const GByte *data() const
728 : {
729 35883 : return m_oVec.data();
730 : }
731 :
732 993 : inline GByte operator[](size_t idx) const
733 : {
734 993 : return m_oVec[idx];
735 : }
736 :
737 53289 : inline GByte &operator[](size_t idx)
738 : {
739 53289 : return m_oVec[idx];
740 : }
741 : };
742 :
743 : /************************************************************************/
744 : /* ZarrArray */
745 : /************************************************************************/
746 :
747 : class ZarrArray CPL_NON_FINAL : public GDALPamMDArray
748 : {
749 : protected:
750 : std::shared_ptr<ZarrSharedResource> m_poSharedResource;
751 : const std::vector<std::shared_ptr<GDALDimension>> m_aoDims;
752 : const GDALExtendedDataType m_oType;
753 : const std::vector<DtypeElt> m_aoDtypeElts;
754 : const std::vector<GUInt64> m_anBlockSize;
755 : CPLStringList m_aosStructuralInfo{};
756 : CPLJSONObject m_dtype{};
757 : GByte *m_pabyNoData = nullptr;
758 : std::string m_osDimSeparator{"."};
759 : std::string m_osFilename{};
760 : size_t m_nTileSize = 0;
761 : mutable ZarrByteVectorQuickResize m_abyRawTileData{};
762 : mutable ZarrByteVectorQuickResize m_abyDecodedTileData{};
763 : mutable std::vector<uint64_t> m_anCachedTiledIndices{};
764 : mutable bool m_bCachedTiledValid = false;
765 : mutable bool m_bCachedTiledEmpty = false;
766 : mutable bool m_bDirtyTile = false;
767 : bool m_bUseOptimizedCodePaths = true;
768 : mutable ZarrAttributeGroup m_oAttrGroup;
769 : mutable std::shared_ptr<OGRSpatialReference> m_poSRS{};
770 : mutable bool m_bAllocateWorkingBuffersDone = false;
771 : mutable bool m_bWorkingBuffersOK = false;
772 : bool m_bUpdatable = false;
773 : bool m_bDefinitionModified = false;
774 : bool m_bSRSModified = false;
775 : bool m_bNew = false;
776 : std::string m_osUnit{};
777 : bool m_bUnitModified = false;
778 : double m_dfOffset = 0.0;
779 : bool m_bHasOffset = false;
780 : bool m_bOffsetModified = false;
781 : double m_dfScale = 1.0;
782 : bool m_bHasScale = false;
783 : bool m_bScaleModified = false;
784 : std::weak_ptr<ZarrGroupBase> m_poGroupWeak{};
785 : uint64_t m_nTotalTileCount = 0;
786 : mutable bool m_bHasTriedCacheTilePresenceArray = false;
787 : mutable std::shared_ptr<GDALMDArray> m_poCacheTilePresenceArray{};
788 : mutable std::mutex m_oMutex{};
789 :
790 : struct CachedTile
791 : {
792 : ZarrByteVectorQuickResize abyDecoded{};
793 : };
794 :
795 : mutable std::map<uint64_t, CachedTile> m_oMapTileIndexToCachedTile{};
796 :
797 : static uint64_t
798 : ComputeTileCount(const std::string &osName,
799 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
800 : const std::vector<GUInt64> &anBlockSize);
801 :
802 : ZarrArray(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
803 : const std::string &osParentName, const std::string &osName,
804 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
805 : const GDALExtendedDataType &oType,
806 : const std::vector<DtypeElt> &aoDtypeElts,
807 : const std::vector<GUInt64> &anBlockSize);
808 :
809 : virtual bool LoadTileData(const uint64_t *tileIndices,
810 : bool &bMissingTileOut) const = 0;
811 :
812 : void BlockTranspose(const ZarrByteVectorQuickResize &abySrc,
813 : ZarrByteVectorQuickResize &abyDst, bool bDecode) const;
814 :
815 : virtual bool AllocateWorkingBuffers() const = 0;
816 :
817 : void SerializeNumericNoData(CPLJSONObject &oRoot) const;
818 :
819 : void DeallocateDecodedTileData();
820 :
821 : virtual std::string GetDataDirectory() const = 0;
822 :
823 : virtual CPLStringList
824 : GetTileIndicesFromFilename(const char *pszFilename) const = 0;
825 :
826 : virtual bool FlushDirtyTile() const = 0;
827 :
828 : std::shared_ptr<GDALMDArray> OpenTilePresenceCache(bool bCanCreate) const;
829 :
830 : void NotifyChildrenOfRenaming() override;
831 :
832 : void NotifyChildrenOfDeletion() override;
833 :
834 : static void EncodeElt(const std::vector<DtypeElt> &elts, const GByte *pSrc,
835 : GByte *pDst);
836 :
837 : // Disable copy constructor and assignment operator
838 : ZarrArray(const ZarrArray &) = delete;
839 : ZarrArray &operator=(const ZarrArray &) = delete;
840 :
841 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
842 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
843 : const GDALExtendedDataType &bufferDataType,
844 : void *pDstBuffer) const override;
845 :
846 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
847 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
848 : const GDALExtendedDataType &bufferDataType,
849 : const void *pSrcBuffer) override;
850 :
851 : bool IsEmptyTile(const ZarrByteVectorQuickResize &abyTile) const;
852 :
853 : bool IAdviseReadCommon(const GUInt64 *arrayStartIdx, const size_t *count,
854 : CSLConstList papszOptions,
855 : std::vector<uint64_t> &anIndicesCur,
856 : int &nThreadsMax,
857 : std::vector<uint64_t> &anReqTilesIndices,
858 : size_t &nReqTiles) const;
859 :
860 : CPLJSONObject SerializeSpecialAttributes();
861 :
862 : virtual std::string
863 : BuildTileFilename(const uint64_t *tileIndices) const = 0;
864 :
865 : bool SetStatistics(bool bApproxStats, double dfMin, double dfMax,
866 : double dfMean, double dfStdDev, GUInt64 nValidCount,
867 : CSLConstList papszOptions) override;
868 :
869 : public:
870 : ~ZarrArray() override;
871 :
872 : static bool ParseChunkSize(const CPLJSONArray &oChunks,
873 : const GDALExtendedDataType &oType,
874 : std::vector<GUInt64> &anBlockSize);
875 :
876 : static bool FillBlockSize(
877 : const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
878 : const GDALExtendedDataType &oDataType,
879 : std::vector<GUInt64> &anBlockSize, CSLConstList papszOptions);
880 :
881 97 : bool IsWritable() const override
882 : {
883 97 : return m_bUpdatable;
884 : }
885 :
886 1911 : const std::string &GetFilename() const override
887 : {
888 1911 : return m_osFilename;
889 : }
890 :
891 : const std::vector<std::shared_ptr<GDALDimension>> &
892 12518 : GetDimensions() const override
893 : {
894 12518 : return m_aoDims;
895 : }
896 :
897 27443 : const GDALExtendedDataType &GetDataType() const override
898 : {
899 27443 : return m_oType;
900 : }
901 :
902 523 : std::vector<GUInt64> GetBlockSize() const override
903 : {
904 523 : return m_anBlockSize;
905 : }
906 :
907 13 : CSLConstList GetStructuralInfo() const override
908 : {
909 13 : return m_aosStructuralInfo.List();
910 : }
911 :
912 22109 : const void *GetRawNoDataValue() const override
913 : {
914 22109 : return m_pabyNoData;
915 : }
916 :
917 77 : const std::string &GetUnit() const override
918 : {
919 77 : return m_osUnit;
920 : }
921 :
922 : bool SetUnit(const std::string &osUnit) override;
923 :
924 53 : void RegisterUnit(const std::string &osUnit)
925 : {
926 53 : m_osUnit = osUnit;
927 53 : }
928 :
929 1195 : void RegisterGroup(const std::weak_ptr<ZarrGroupBase> &group)
930 : {
931 1195 : m_poGroupWeak = group;
932 1195 : }
933 :
934 : double GetOffset(bool *pbHasOffset,
935 : GDALDataType *peStorageType) const override;
936 :
937 : double GetScale(bool *pbHasScale,
938 : GDALDataType *peStorageType) const override;
939 :
940 : bool SetOffset(double dfOffset, GDALDataType eStorageType) override;
941 :
942 : bool SetScale(double dfScale, GDALDataType eStorageType) override;
943 :
944 : std::vector<std::shared_ptr<GDALMDArray>>
945 : GetCoordinateVariables() const override;
946 :
947 : bool Resize(const std::vector<GUInt64> &anNewDimSizes,
948 : CSLConstList) override;
949 :
950 3 : void RegisterOffset(double dfOffset)
951 : {
952 3 : m_bHasOffset = true;
953 3 : m_dfOffset = dfOffset;
954 3 : }
955 :
956 3 : void RegisterScale(double dfScale)
957 : {
958 3 : m_bHasScale = true;
959 3 : m_dfScale = dfScale;
960 3 : }
961 :
962 : bool SetRawNoDataValue(const void *pRawNoData) override;
963 :
964 : void RegisterNoDataValue(const void *);
965 :
966 1195 : void SetFilename(const std::string &osFilename)
967 : {
968 1195 : m_osFilename = osFilename;
969 1195 : }
970 :
971 1195 : void SetDimSeparator(const std::string &osDimSeparator)
972 : {
973 1195 : m_osDimSeparator = osDimSeparator;
974 1195 : }
975 :
976 : void ParseSpecialAttributes(const std::shared_ptr<GDALGroup> &poGroup,
977 : CPLJSONObject &oAttributes);
978 :
979 769 : void SetAttributes(const CPLJSONObject &attrs)
980 : {
981 769 : m_oAttrGroup.Init(attrs, m_bUpdatable);
982 769 : }
983 :
984 27 : void SetSRS(const std::shared_ptr<OGRSpatialReference> &srs)
985 : {
986 27 : m_poSRS = srs;
987 27 : }
988 :
989 : std::shared_ptr<GDALAttribute>
990 64 : GetAttribute(const std::string &osName) const override
991 : {
992 64 : return m_oAttrGroup.GetAttribute(osName);
993 : }
994 :
995 : std::vector<std::shared_ptr<GDALAttribute>>
996 117 : GetAttributes(CSLConstList papszOptions) const override
997 : {
998 117 : return m_oAttrGroup.GetAttributes(papszOptions);
999 : }
1000 :
1001 : std::shared_ptr<GDALAttribute>
1002 : CreateAttribute(const std::string &osName,
1003 : const std::vector<GUInt64> &anDimensions,
1004 : const GDALExtendedDataType &oDataType,
1005 : CSLConstList papszOptions = nullptr) override;
1006 :
1007 : bool DeleteAttribute(const std::string &osName,
1008 : CSLConstList papszOptions = nullptr) override;
1009 :
1010 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
1011 :
1012 : bool SetSpatialRef(const OGRSpatialReference *poSRS) override;
1013 :
1014 1195 : void SetUpdatable(bool bUpdatable)
1015 : {
1016 1195 : m_bUpdatable = bUpdatable;
1017 1195 : }
1018 :
1019 1195 : void SetDtype(const CPLJSONObject &dtype)
1020 : {
1021 1195 : m_dtype = dtype;
1022 1195 : }
1023 :
1024 441 : void SetDefinitionModified(bool bModified)
1025 : {
1026 441 : m_bDefinitionModified = bModified;
1027 441 : }
1028 :
1029 426 : void SetNew(bool bNew)
1030 : {
1031 426 : m_bNew = bNew;
1032 426 : }
1033 :
1034 : bool Rename(const std::string &osNewName) override;
1035 :
1036 : void ParentRenamed(const std::string &osNewParentFullName) override;
1037 :
1038 : virtual void Flush() = 0;
1039 :
1040 0 : std::shared_ptr<GDALGroup> GetRootGroup() const override
1041 : {
1042 0 : return m_poSharedResource->GetRootGroup();
1043 : }
1044 :
1045 : bool CacheTilePresence();
1046 :
1047 55 : void SetStructuralInfo(const char *pszKey, const char *pszValue)
1048 : {
1049 55 : m_aosStructuralInfo.SetNameValue(pszKey, pszValue);
1050 55 : }
1051 :
1052 : static void DecodeSourceElt(const std::vector<DtypeElt> &elts,
1053 : const GByte *pSrc, GByte *pDst);
1054 :
1055 : static void GetDimensionTypeDirection(CPLJSONObject &oAttributes,
1056 : std::string &osType,
1057 : std::string &osDirection);
1058 : };
1059 :
1060 : /************************************************************************/
1061 : /* ZarrV2Array */
1062 : /************************************************************************/
1063 :
1064 : class ZarrV2Array final : public ZarrArray
1065 : {
1066 : CPLJSONObject m_oCompressorJSon{};
1067 : const CPLCompressor *m_psCompressor = nullptr;
1068 : std::string m_osDecompressorId{};
1069 : const CPLCompressor *m_psDecompressor = nullptr;
1070 : CPLJSONArray m_oFiltersArray{}; // ZarrV2 specific
1071 : bool m_bFortranOrder = false;
1072 : mutable ZarrByteVectorQuickResize
1073 : m_abyTmpRawTileData{}; // used for Fortran order
1074 :
1075 : ZarrV2Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1076 : const std::string &osParentName, const std::string &osName,
1077 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1078 : const GDALExtendedDataType &oType,
1079 : const std::vector<DtypeElt> &aoDtypeElts,
1080 : const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
1081 :
1082 : void Serialize();
1083 :
1084 : bool LoadTileData(const uint64_t *tileIndices, bool bUseMutex,
1085 : const CPLCompressor *psDecompressor,
1086 : ZarrByteVectorQuickResize &abyRawTileData,
1087 : ZarrByteVectorQuickResize &abyTmpRawTileData,
1088 : ZarrByteVectorQuickResize &abyDecodedTileData,
1089 : bool &bMissingTileOut) const;
1090 :
1091 : bool NeedDecodedBuffer() const;
1092 :
1093 : bool
1094 : AllocateWorkingBuffers(ZarrByteVectorQuickResize &abyRawTileData,
1095 : ZarrByteVectorQuickResize &abyTmpRawTileData,
1096 : ZarrByteVectorQuickResize &abyDecodedTileData) const;
1097 :
1098 : // Disable copy constructor and assignment operator
1099 : ZarrV2Array(const ZarrV2Array &) = delete;
1100 : ZarrV2Array &operator=(const ZarrV2Array &) = delete;
1101 :
1102 : public:
1103 : ~ZarrV2Array() override;
1104 :
1105 : static std::shared_ptr<ZarrV2Array>
1106 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1107 : const std::string &osParentName, const std::string &osName,
1108 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1109 : const GDALExtendedDataType &oType,
1110 : const std::vector<DtypeElt> &aoDtypeElts,
1111 : const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
1112 :
1113 : void SetCompressorJson(const CPLJSONObject &oCompressor);
1114 :
1115 913 : void SetCompressorDecompressor(const std::string &osDecompressorId,
1116 : const CPLCompressor *psComp,
1117 : const CPLCompressor *psDecomp)
1118 : {
1119 913 : m_psCompressor = psComp;
1120 913 : m_osDecompressorId = osDecompressorId;
1121 913 : m_psDecompressor = psDecomp;
1122 913 : }
1123 :
1124 : void SetFilters(const CPLJSONArray &oFiltersArray);
1125 :
1126 : void Flush() override;
1127 :
1128 : protected:
1129 : std::string GetDataDirectory() const override;
1130 :
1131 : CPLStringList
1132 : GetTileIndicesFromFilename(const char *pszFilename) const override;
1133 :
1134 : bool FlushDirtyTile() const override;
1135 :
1136 : std::string BuildTileFilename(const uint64_t *tileIndices) const override;
1137 :
1138 : bool AllocateWorkingBuffers() const override;
1139 :
1140 : bool LoadTileData(const uint64_t *tileIndices,
1141 : bool &bMissingTileOut) const override;
1142 :
1143 : bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
1144 : CSLConstList papszOptions) const override;
1145 : };
1146 :
1147 : /************************************************************************/
1148 : /* ZarrArrayMetadata */
1149 : /************************************************************************/
1150 :
1151 : struct ZarrArrayMetadata
1152 : {
1153 : DtypeElt oElt{};
1154 : std::vector<size_t> anBlockSizes{};
1155 :
1156 10833 : size_t GetEltCount() const
1157 : {
1158 10833 : size_t n = 1;
1159 32121 : for (auto i : anBlockSizes)
1160 21260 : n *= i;
1161 10667 : return n;
1162 : }
1163 : };
1164 :
1165 : /************************************************************************/
1166 : /* ZarrV3Codec */
1167 : /************************************************************************/
1168 :
1169 396 : class ZarrV3Codec CPL_NON_FINAL
1170 : {
1171 : protected:
1172 : const std::string m_osName;
1173 : CPLJSONObject m_oConfiguration{};
1174 : ZarrArrayMetadata m_oInputArrayMetadata{};
1175 :
1176 : ZarrV3Codec(const std::string &osName);
1177 :
1178 : public:
1179 : virtual ~ZarrV3Codec() = 0;
1180 :
1181 : enum class IOType
1182 : {
1183 : BYTES,
1184 : ARRAY
1185 : };
1186 :
1187 : virtual IOType GetInputType() const = 0;
1188 : virtual IOType GetOutputType() const = 0;
1189 :
1190 : virtual bool
1191 : InitFromConfiguration(const CPLJSONObject &configuration,
1192 : const ZarrArrayMetadata &oInputArrayMetadata,
1193 : ZarrArrayMetadata &oOutputArrayMetadata) = 0;
1194 :
1195 : virtual std::unique_ptr<ZarrV3Codec> Clone() const = 0;
1196 :
1197 55 : virtual bool IsNoOp() const
1198 : {
1199 55 : return false;
1200 : }
1201 :
1202 : virtual bool Encode(const ZarrByteVectorQuickResize &abySrc,
1203 : ZarrByteVectorQuickResize &abyDst) const = 0;
1204 : virtual bool Decode(const ZarrByteVectorQuickResize &abySrc,
1205 : ZarrByteVectorQuickResize &abyDst) const = 0;
1206 :
1207 388 : const std::string &GetName() const
1208 : {
1209 388 : return m_osName;
1210 : }
1211 :
1212 : const CPLJSONObject &GetConfiguration() const
1213 : {
1214 : return m_oConfiguration;
1215 : }
1216 : };
1217 :
1218 : /************************************************************************/
1219 : /* ZarrV3CodecAbstractCompressor */
1220 : /************************************************************************/
1221 :
1222 : class ZarrV3CodecAbstractCompressor CPL_NON_FINAL : public ZarrV3Codec
1223 : {
1224 : protected:
1225 : CPLStringList m_aosCompressorOptions{};
1226 : const CPLCompressor *m_pDecompressor = nullptr;
1227 : const CPLCompressor *m_pCompressor = nullptr;
1228 :
1229 : explicit ZarrV3CodecAbstractCompressor(const std::string &osName);
1230 :
1231 : ZarrV3CodecAbstractCompressor(const ZarrV3CodecAbstractCompressor &) =
1232 : delete;
1233 : ZarrV3CodecAbstractCompressor &
1234 : operator=(const ZarrV3CodecAbstractCompressor &) = delete;
1235 :
1236 : public:
1237 55 : IOType GetInputType() const override
1238 : {
1239 55 : return IOType::BYTES;
1240 : }
1241 :
1242 55 : IOType GetOutputType() const override
1243 : {
1244 55 : return IOType::BYTES;
1245 : }
1246 :
1247 : bool Encode(const ZarrByteVectorQuickResize &abySrc,
1248 : ZarrByteVectorQuickResize &abyDst) const override;
1249 : bool Decode(const ZarrByteVectorQuickResize &abySrc,
1250 : ZarrByteVectorQuickResize &abyDst) const override;
1251 : };
1252 :
1253 : /************************************************************************/
1254 : /* ZarrV3CodecGZip */
1255 : /************************************************************************/
1256 :
1257 : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/gzip/v1.0.html
1258 : class ZarrV3CodecGZip final : public ZarrV3CodecAbstractCompressor
1259 : {
1260 : public:
1261 : static constexpr const char *NAME = "gzip";
1262 :
1263 : ZarrV3CodecGZip();
1264 :
1265 : static CPLJSONObject GetConfiguration(int nLevel);
1266 :
1267 : bool
1268 : InitFromConfiguration(const CPLJSONObject &configuration,
1269 : const ZarrArrayMetadata &oInputArrayMetadata,
1270 : ZarrArrayMetadata &oOutputArrayMetadata) override;
1271 :
1272 : std::unique_ptr<ZarrV3Codec> Clone() const override;
1273 : };
1274 :
1275 : /************************************************************************/
1276 : /* ZarrV3CodecBlosc */
1277 : /************************************************************************/
1278 :
1279 : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/blosc/v1.0.html
1280 : class ZarrV3CodecBlosc final : public ZarrV3CodecAbstractCompressor
1281 : {
1282 : public:
1283 : static constexpr const char *NAME = "blosc";
1284 :
1285 : ZarrV3CodecBlosc();
1286 :
1287 : static CPLJSONObject GetConfiguration(const char *cname, int clevel,
1288 : const char *shuffle, int typesize,
1289 : int blocksize);
1290 :
1291 : bool
1292 : InitFromConfiguration(const CPLJSONObject &configuration,
1293 : const ZarrArrayMetadata &oInputArrayMetadata,
1294 : ZarrArrayMetadata &oOutputArrayMetadata) override;
1295 :
1296 : std::unique_ptr<ZarrV3Codec> Clone() const override;
1297 : };
1298 :
1299 : /************************************************************************/
1300 : /* ZarrV3CodecZstd */
1301 : /************************************************************************/
1302 :
1303 : // Implements https://github.com/zarr-developers/zarr-specs/pull/256
1304 : class ZarrV3CodecZstd final : public ZarrV3CodecAbstractCompressor
1305 : {
1306 : public:
1307 : static constexpr const char *NAME = "zstd";
1308 :
1309 : ZarrV3CodecZstd();
1310 :
1311 : static CPLJSONObject GetConfiguration(int level, bool checksum);
1312 :
1313 : bool
1314 : InitFromConfiguration(const CPLJSONObject &configuration,
1315 : const ZarrArrayMetadata &oInputArrayMetadata,
1316 : ZarrArrayMetadata &oOutputArrayMetadata) override;
1317 :
1318 : std::unique_ptr<ZarrV3Codec> Clone() const override;
1319 : };
1320 :
1321 : /************************************************************************/
1322 : /* ZarrV3CodecBytes */
1323 : /************************************************************************/
1324 :
1325 : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/bytes/v1.0.html
1326 : class ZarrV3CodecBytes final : public ZarrV3Codec
1327 : {
1328 : bool m_bLittle = true;
1329 :
1330 : public:
1331 : static constexpr const char *NAME = "bytes";
1332 :
1333 : ZarrV3CodecBytes();
1334 :
1335 253 : IOType GetInputType() const override
1336 : {
1337 253 : return IOType::ARRAY;
1338 : }
1339 :
1340 253 : IOType GetOutputType() const override
1341 : {
1342 253 : return IOType::BYTES;
1343 : }
1344 :
1345 : static CPLJSONObject GetConfiguration(bool bLittle);
1346 :
1347 : bool
1348 : InitFromConfiguration(const CPLJSONObject &configuration,
1349 : const ZarrArrayMetadata &oInputArrayMetadata,
1350 : ZarrArrayMetadata &oOutputArrayMetadata) override;
1351 :
1352 : #if CPL_IS_LSB
1353 301 : bool IsNoOp() const override
1354 : {
1355 301 : return m_oInputArrayMetadata.oElt.nativeSize == 1 || m_bLittle;
1356 : }
1357 : #else
1358 : bool IsNoOp() const override
1359 : {
1360 : return m_oInputArrayMetadata.oElt.nativeSize == 1 || !m_bLittle;
1361 : }
1362 : #endif
1363 :
1364 : std::unique_ptr<ZarrV3Codec> Clone() const override;
1365 :
1366 : bool Encode(const ZarrByteVectorQuickResize &abySrc,
1367 : ZarrByteVectorQuickResize &abyDst) const override;
1368 : bool Decode(const ZarrByteVectorQuickResize &abySrc,
1369 : ZarrByteVectorQuickResize &abyDst) const override;
1370 : };
1371 :
1372 : /************************************************************************/
1373 : /* ZarrV3CodecTranspose */
1374 : /************************************************************************/
1375 :
1376 : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/transpose/v1.0.html
1377 : class ZarrV3CodecTranspose final : public ZarrV3Codec
1378 : {
1379 : // m_anOrder is such that dest_shape[i] = source_shape[m_anOrder[i]]
1380 : // where source_shape[] is the size of the array before the Encode() operation
1381 : // and dest_shape[] its size after.
1382 : // m_anOrder[] describes a bijection of [0,N-1] to [0,N-1]
1383 : std::vector<int> m_anOrder{};
1384 :
1385 : // m_anReverseOrder is such that m_anReverseOrder[m_anOrder[i]] = i
1386 : std::vector<int> m_anReverseOrder{};
1387 :
1388 : bool Transpose(const ZarrByteVectorQuickResize &abySrc,
1389 : ZarrByteVectorQuickResize &abyDst,
1390 : bool bEncodeDirection) const;
1391 :
1392 : public:
1393 : static constexpr const char *NAME = "transpose";
1394 :
1395 : ZarrV3CodecTranspose();
1396 :
1397 80 : IOType GetInputType() const override
1398 : {
1399 80 : return IOType::ARRAY;
1400 : }
1401 :
1402 80 : IOType GetOutputType() const override
1403 : {
1404 80 : return IOType::ARRAY;
1405 : }
1406 :
1407 : static CPLJSONObject GetConfiguration(const std::vector<int> &anOrder);
1408 : static CPLJSONObject GetConfiguration(const std::string &osOrder);
1409 :
1410 : bool
1411 : InitFromConfiguration(const CPLJSONObject &configuration,
1412 : const ZarrArrayMetadata &oInputArrayMetadata,
1413 : ZarrArrayMetadata &oOutputArrayMetadata) override;
1414 :
1415 : bool IsNoOp() const override;
1416 :
1417 : std::unique_ptr<ZarrV3Codec> Clone() const override;
1418 :
1419 : bool Encode(const ZarrByteVectorQuickResize &abySrc,
1420 : ZarrByteVectorQuickResize &abyDst) const override;
1421 : bool Decode(const ZarrByteVectorQuickResize &abySrc,
1422 : ZarrByteVectorQuickResize &abyDst) const override;
1423 : };
1424 :
1425 : /************************************************************************/
1426 : /* ZarrV3CodecSequence */
1427 : /************************************************************************/
1428 :
1429 : class ZarrV3CodecSequence
1430 : {
1431 : const ZarrArrayMetadata m_oInputArrayMetadata;
1432 : std::vector<std::unique_ptr<ZarrV3Codec>> m_apoCodecs{};
1433 : CPLJSONObject m_oCodecArray{};
1434 : ZarrByteVectorQuickResize m_abyTmp{};
1435 :
1436 : bool AllocateBuffer(ZarrByteVectorQuickResize &abyBuffer);
1437 :
1438 : public:
1439 269 : explicit ZarrV3CodecSequence(const ZarrArrayMetadata &oInputArrayMetadata)
1440 269 : : m_oInputArrayMetadata(oInputArrayMetadata)
1441 : {
1442 269 : }
1443 :
1444 : // This method is not thread safe due to cloning a JSON object
1445 : std::unique_ptr<ZarrV3CodecSequence> Clone() const;
1446 :
1447 : bool InitFromJson(const CPLJSONObject &oCodecs);
1448 :
1449 155 : const CPLJSONObject &GetJSon() const
1450 : {
1451 155 : return m_oCodecArray;
1452 : }
1453 :
1454 : bool Encode(ZarrByteVectorQuickResize &abyBuffer);
1455 : bool Decode(ZarrByteVectorQuickResize &abyBuffer);
1456 : };
1457 :
1458 : /************************************************************************/
1459 : /* ZarrV3Array */
1460 : /************************************************************************/
1461 :
1462 : class ZarrV3Array final : public ZarrArray
1463 : {
1464 : bool m_bV2ChunkKeyEncoding = false;
1465 : std::unique_ptr<ZarrV3CodecSequence> m_poCodecs{};
1466 :
1467 : ZarrV3Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1468 : const std::string &osParentName, const std::string &osName,
1469 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1470 : const GDALExtendedDataType &oType,
1471 : const std::vector<DtypeElt> &aoDtypeElts,
1472 : const std::vector<GUInt64> &anBlockSize);
1473 :
1474 : void Serialize(const CPLJSONObject &oAttrs);
1475 :
1476 : bool NeedDecodedBuffer() const;
1477 :
1478 : bool
1479 : AllocateWorkingBuffers(ZarrByteVectorQuickResize &abyRawTileData,
1480 : ZarrByteVectorQuickResize &abyDecodedTileData) const;
1481 :
1482 : bool LoadTileData(const uint64_t *tileIndices, bool bUseMutex,
1483 : ZarrV3CodecSequence *poCodecs,
1484 : ZarrByteVectorQuickResize &abyRawTileData,
1485 : ZarrByteVectorQuickResize &abyDecodedTileData,
1486 : bool &bMissingTileOut) const;
1487 :
1488 : public:
1489 : ~ZarrV3Array() override;
1490 :
1491 : static std::shared_ptr<ZarrV3Array>
1492 : Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
1493 : const std::string &osParentName, const std::string &osName,
1494 : const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
1495 : const GDALExtendedDataType &oType,
1496 : const std::vector<DtypeElt> &aoDtypeElts,
1497 : const std::vector<GUInt64> &anBlockSize);
1498 :
1499 161 : void SetIsV2ChunkKeyEncoding(bool b)
1500 : {
1501 161 : m_bV2ChunkKeyEncoding = b;
1502 161 : }
1503 :
1504 253 : void SetCodecs(std::unique_ptr<ZarrV3CodecSequence> &&poCodecs)
1505 : {
1506 253 : m_poCodecs = std::move(poCodecs);
1507 253 : }
1508 :
1509 : void Flush() override;
1510 :
1511 : protected:
1512 : std::string GetDataDirectory() const override;
1513 :
1514 : CPLStringList
1515 : GetTileIndicesFromFilename(const char *pszFilename) const override;
1516 :
1517 : bool AllocateWorkingBuffers() const override;
1518 :
1519 : bool FlushDirtyTile() const override;
1520 :
1521 : std::string BuildTileFilename(const uint64_t *tileIndices) const override;
1522 :
1523 : bool LoadTileData(const uint64_t *tileIndices,
1524 : bool &bMissingTileOut) const override;
1525 :
1526 : bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
1527 : CSLConstList papszOptions) const override;
1528 : };
1529 :
1530 : #endif // ZARR_H
|