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