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