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