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