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