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