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 : #include "zarr.h"
14 :
15 : #include <algorithm>
16 : #include <cassert>
17 : #include <map>
18 :
19 : constexpr const char *ATTRIBUTE_GROUP_SUFFIX = "/_GLOBAL_";
20 :
21 : /************************************************************************/
22 : /* ZarrAttributeGroup::ZarrAttributeGroup() */
23 : /************************************************************************/
24 :
25 6937 : ZarrAttributeGroup::ZarrAttributeGroup(const std::string &osParentName,
26 6937 : bool bContainerIsGroup)
27 : : m_bContainerIsGroup(bContainerIsGroup),
28 : m_poGroup(MEMGroup::Create(
29 : bContainerIsGroup
30 13874 : ? (osParentName == "/" ? ATTRIBUTE_GROUP_SUFFIX
31 : : osParentName + ATTRIBUTE_GROUP_SUFFIX)
32 : : osParentName,
33 13874 : nullptr))
34 : {
35 6937 : }
36 :
37 : /************************************************************************/
38 : /* ZarrAttributeGroup::Init() */
39 : /************************************************************************/
40 :
41 3758 : void ZarrAttributeGroup::Init(const CPLJSONObject &obj, bool bUpdatable)
42 : {
43 3758 : if (obj.GetType() != CPLJSONObject::Type::Object)
44 92 : return;
45 7332 : const auto children = obj.GetChildren();
46 4564 : for (const auto &item : children)
47 : {
48 898 : const auto itemType = item.GetType();
49 898 : bool bDone = false;
50 898 : std::shared_ptr<GDALAttribute> poAttr;
51 898 : switch (itemType)
52 : {
53 444 : case CPLJSONObject::Type::String:
54 : {
55 444 : bDone = true;
56 1776 : poAttr = m_poGroup->CreateAttribute(
57 888 : item.GetName(), {}, GDALExtendedDataType::CreateString(),
58 888 : nullptr);
59 444 : if (poAttr)
60 : {
61 444 : const GUInt64 arrayStartIdx = 0;
62 444 : const size_t count = 1;
63 444 : const GInt64 arrayStep = 0;
64 444 : const GPtrDiff_t bufferStride = 0;
65 1332 : const std::string str = item.ToString();
66 444 : const char *c_str = str.c_str();
67 888 : poAttr->Write(&arrayStartIdx, &count, &arrayStep,
68 444 : &bufferStride, poAttr->GetDataType(), &c_str);
69 : }
70 444 : break;
71 : }
72 31 : case CPLJSONObject::Type::Integer:
73 : {
74 31 : bDone = true;
75 124 : poAttr = m_poGroup->CreateAttribute(
76 62 : item.GetName(), {}, GDALExtendedDataType::Create(GDT_Int32),
77 62 : nullptr);
78 31 : if (poAttr)
79 : {
80 31 : const GUInt64 arrayStartIdx = 0;
81 31 : const size_t count = 1;
82 31 : const GInt64 arrayStep = 0;
83 31 : const GPtrDiff_t bufferStride = 0;
84 31 : const int val = item.ToInteger();
85 62 : poAttr->Write(
86 : &arrayStartIdx, &count, &arrayStep, &bufferStride,
87 62 : GDALExtendedDataType::Create(GDT_Int32), &val);
88 : }
89 31 : break;
90 : }
91 35 : case CPLJSONObject::Type::Long:
92 : {
93 35 : bDone = true;
94 140 : poAttr = m_poGroup->CreateAttribute(
95 70 : item.GetName(), {}, GDALExtendedDataType::Create(GDT_Int64),
96 70 : nullptr);
97 35 : if (poAttr)
98 : {
99 35 : const GUInt64 arrayStartIdx = 0;
100 35 : const size_t count = 1;
101 35 : const GInt64 arrayStep = 0;
102 35 : const GPtrDiff_t bufferStride = 0;
103 35 : const int64_t val = item.ToLong();
104 70 : poAttr->Write(
105 : &arrayStartIdx, &count, &arrayStep, &bufferStride,
106 70 : GDALExtendedDataType::Create(GDT_Int64), &val);
107 : }
108 35 : break;
109 : }
110 69 : case CPLJSONObject::Type::Double:
111 : {
112 69 : bDone = true;
113 276 : poAttr = m_poGroup->CreateAttribute(
114 138 : item.GetName(), {},
115 207 : GDALExtendedDataType::Create(GDT_Float64), nullptr);
116 69 : if (poAttr)
117 : {
118 69 : const GUInt64 arrayStartIdx = 0;
119 69 : const size_t count = 1;
120 69 : const GInt64 arrayStep = 0;
121 69 : const GPtrDiff_t bufferStride = 0;
122 69 : const double val = item.ToDouble();
123 138 : poAttr->Write(
124 : &arrayStartIdx, &count, &arrayStep, &bufferStride,
125 138 : GDALExtendedDataType::Create(GDT_Float64), &val);
126 : }
127 69 : break;
128 : }
129 197 : case CPLJSONObject::Type::Array:
130 : {
131 394 : const auto array = item.ToArray();
132 197 : bool isFirst = true;
133 197 : bool isString = false;
134 197 : bool isNumeric = false;
135 197 : bool foundInt64 = false;
136 197 : bool foundDouble = false;
137 197 : bool mixedType = false;
138 197 : size_t countItems = 0;
139 660 : for (const auto &subItem : array)
140 : {
141 463 : const auto subItemType = subItem.GetType();
142 463 : if (subItemType == CPLJSONObject::Type::String)
143 : {
144 91 : if (isFirst)
145 : {
146 45 : isString = true;
147 : }
148 46 : else if (!isString)
149 : {
150 0 : mixedType = true;
151 0 : break;
152 : }
153 91 : countItems++;
154 : }
155 372 : else if (subItemType == CPLJSONObject::Type::Integer ||
156 224 : subItemType == CPLJSONObject::Type::Long ||
157 : subItemType == CPLJSONObject::Type::Double)
158 : {
159 333 : if (isFirst)
160 : {
161 113 : isNumeric = true;
162 : }
163 220 : else if (!isNumeric)
164 : {
165 5 : mixedType = true;
166 5 : break;
167 : }
168 328 : if (subItemType == CPLJSONObject::Type::Double)
169 185 : foundDouble = true;
170 143 : else if (subItemType == CPLJSONObject::Type::Long)
171 60 : foundInt64 = true;
172 328 : countItems++;
173 : }
174 : else
175 : {
176 39 : mixedType = true;
177 39 : break;
178 : }
179 419 : isFirst = false;
180 : }
181 :
182 197 : if (!mixedType && !isFirst)
183 : {
184 153 : bDone = true;
185 765 : poAttr = m_poGroup->CreateAttribute(
186 306 : item.GetName(), {countItems},
187 367 : isString ? GDALExtendedDataType::CreateString()
188 : : GDALExtendedDataType::Create(
189 : foundDouble ? GDT_Float64
190 61 : : foundInt64 ? GDT_Int64
191 : : GDT_Int32),
192 306 : nullptr);
193 153 : if (poAttr)
194 : {
195 153 : size_t idx = 0;
196 567 : for (const auto &subItem : array)
197 : {
198 414 : const GUInt64 arrayStartIdx = idx;
199 414 : const size_t count = 1;
200 414 : const GInt64 arrayStep = 0;
201 414 : const GPtrDiff_t bufferStride = 0;
202 414 : const auto subItemType = subItem.GetType();
203 : switch (subItemType)
204 : {
205 86 : case CPLJSONObject::Type::String:
206 : {
207 258 : const std::string str = subItem.ToString();
208 86 : const char *c_str = str.c_str();
209 172 : poAttr->Write(&arrayStartIdx, &count,
210 : &arrayStep, &bufferStride,
211 86 : poAttr->GetDataType(),
212 : &c_str);
213 86 : break;
214 : }
215 83 : case CPLJSONObject::Type::Integer:
216 : {
217 83 : const int val = subItem.ToInteger();
218 166 : poAttr->Write(
219 : &arrayStartIdx, &count, &arrayStep,
220 : &bufferStride,
221 166 : GDALExtendedDataType::Create(GDT_Int32),
222 : &val);
223 83 : break;
224 : }
225 60 : case CPLJSONObject::Type::Long:
226 : {
227 60 : const int64_t val = subItem.ToLong();
228 120 : poAttr->Write(
229 : &arrayStartIdx, &count, &arrayStep,
230 : &bufferStride,
231 120 : GDALExtendedDataType::Create(GDT_Int64),
232 : &val);
233 60 : break;
234 : }
235 185 : case CPLJSONObject::Type::Double:
236 : {
237 185 : const double val = subItem.ToDouble();
238 370 : poAttr->Write(&arrayStartIdx, &count,
239 : &arrayStep, &bufferStride,
240 370 : GDALExtendedDataType::Create(
241 : GDT_Float64),
242 : &val);
243 185 : break;
244 : }
245 0 : default:
246 : // Ignore other JSON object types
247 0 : break;
248 : }
249 414 : ++idx;
250 : }
251 : }
252 : }
253 197 : break;
254 : }
255 122 : default:
256 : // Ignore other JSON object types
257 122 : break;
258 : }
259 :
260 898 : if (!bDone)
261 : {
262 166 : constexpr size_t nMaxStringLength = 0;
263 : const auto eDT = GDALExtendedDataType::CreateString(
264 332 : nMaxStringLength, GEDTST_JSON);
265 : poAttr =
266 166 : m_poGroup->CreateAttribute(item.GetName(), {}, eDT, nullptr);
267 166 : if (poAttr)
268 : {
269 166 : const GUInt64 arrayStartIdx = 0;
270 166 : const size_t count = 1;
271 166 : const GInt64 arrayStep = 0;
272 166 : const GPtrDiff_t bufferStride = 0;
273 498 : const std::string str = item.ToString();
274 166 : const char *c_str = str.c_str();
275 332 : poAttr->Write(&arrayStartIdx, &count, &arrayStep, &bufferStride,
276 166 : poAttr->GetDataType(), &c_str);
277 : }
278 : }
279 :
280 1796 : auto poMemAttr = std::dynamic_pointer_cast<MEMAttribute>(poAttr);
281 898 : if (poMemAttr)
282 898 : poMemAttr->SetModified(false);
283 : }
284 3666 : SetUpdatable(bUpdatable);
285 : }
286 :
287 : /************************************************************************/
288 : /* ZarrAttributeGroup::Serialize() */
289 : /************************************************************************/
290 :
291 599 : CPLJSONObject ZarrAttributeGroup::Serialize() const
292 : {
293 599 : CPLJSONObject o;
294 1198 : const auto attrs = m_poGroup->GetAttributes(nullptr);
295 1132 : for (const auto &attr : attrs)
296 : {
297 533 : const auto &oType = attr->GetDataType();
298 533 : if (oType.GetClass() == GEDTC_STRING)
299 : {
300 660 : const auto anDims = attr->GetDimensionsSize();
301 330 : if (anDims.size() == 0)
302 : {
303 310 : const char *pszStr = attr->ReadAsString();
304 310 : if (pszStr)
305 : {
306 620 : CPLJSONDocument oDoc;
307 335 : if (oType.GetSubType() == GEDTST_JSON &&
308 335 : oDoc.LoadMemory(pszStr))
309 : {
310 25 : o.Add(attr->GetName(), oDoc.GetRoot());
311 : }
312 : else
313 : {
314 285 : o.Add(attr->GetName(), pszStr);
315 : }
316 : }
317 : else
318 : {
319 0 : o.AddNull(attr->GetName());
320 : }
321 : }
322 20 : else if (anDims.size() == 1)
323 : {
324 40 : const auto list = attr->ReadAsStringArray();
325 40 : CPLJSONArray arr;
326 64 : for (int i = 0; i < list.size(); ++i)
327 : {
328 44 : arr.Add(list[i]);
329 : }
330 20 : o.Add(attr->GetName(), arr);
331 : }
332 : else
333 : {
334 0 : CPLError(
335 : CE_Warning, CPLE_AppDefined,
336 : "Cannot serialize attribute %s of dimension count >= 2",
337 0 : attr->GetName().c_str());
338 : }
339 : }
340 203 : else if (oType.GetClass() == GEDTC_NUMERIC)
341 : {
342 406 : const auto anDims = attr->GetDimensionsSize();
343 203 : const auto eDT = oType.GetNumericDataType();
344 203 : if (anDims.size() == 0)
345 : {
346 120 : if (eDT == GDT_Int8 || eDT == GDT_Int16 || eDT == GDT_Int32 ||
347 : eDT == GDT_Int64)
348 : {
349 49 : const int64_t nVal = attr->ReadAsInt64();
350 49 : o.Add(attr->GetName(), static_cast<GInt64>(nVal));
351 : }
352 71 : else if (eDT == GDT_UInt8 || eDT == GDT_UInt16 ||
353 24 : eDT == GDT_UInt32 || eDT == GDT_UInt64)
354 : {
355 55 : const int64_t nVal = attr->ReadAsInt64();
356 55 : o.Add(attr->GetName(), static_cast<uint64_t>(nVal));
357 : }
358 : else
359 : {
360 16 : const double dfVal = attr->ReadAsDouble();
361 16 : o.Add(attr->GetName(), dfVal);
362 : }
363 : }
364 83 : else if (anDims.size() == 1)
365 : {
366 166 : CPLJSONArray arr;
367 83 : if (eDT == GDT_Int8 || eDT == GDT_Int16 || eDT == GDT_Int32 ||
368 : eDT == GDT_Int64)
369 : {
370 96 : const auto list = attr->ReadAsInt64Array();
371 144 : for (const auto nVal : list)
372 : {
373 96 : arr.Add(static_cast<GInt64>(nVal));
374 48 : }
375 : }
376 35 : else if (eDT == GDT_UInt8 || eDT == GDT_UInt16 ||
377 27 : eDT == GDT_UInt32 || eDT == GDT_UInt64)
378 : {
379 32 : const auto list = attr->ReadAsInt64Array();
380 48 : for (const auto nVal : list)
381 : {
382 32 : arr.Add(static_cast<uint64_t>(nVal));
383 16 : }
384 : }
385 : else
386 : {
387 38 : const auto list = attr->ReadAsDoubleArray();
388 65 : for (const auto dfVal : list)
389 : {
390 46 : arr.Add(dfVal);
391 : }
392 : }
393 83 : o.Add(attr->GetName(), arr);
394 : }
395 : else
396 : {
397 0 : CPLError(
398 : CE_Warning, CPLE_AppDefined,
399 : "Cannot serialize attribute %s of dimension count >= 2",
400 0 : attr->GetName().c_str());
401 : }
402 : }
403 : }
404 1198 : return o;
405 : }
406 :
407 : /************************************************************************/
408 : /* ParentRenamed() */
409 : /************************************************************************/
410 :
411 25 : void ZarrAttributeGroup::ParentRenamed(const std::string &osNewParentFullName)
412 : {
413 25 : if (m_bContainerIsGroup)
414 10 : m_poGroup->SetFullName(osNewParentFullName + ATTRIBUTE_GROUP_SUFFIX);
415 : else
416 15 : m_poGroup->SetFullName(osNewParentFullName);
417 50 : const auto attrs = m_poGroup->GetAttributes(nullptr);
418 52 : for (auto &attr : attrs)
419 : {
420 27 : attr->ParentRenamed(m_poGroup->GetFullName());
421 : }
422 25 : }
423 :
424 : /************************************************************************/
425 : /* ParentDeleted() */
426 : /************************************************************************/
427 :
428 14 : void ZarrAttributeGroup::ParentDeleted()
429 : {
430 14 : m_poGroup->Deleted();
431 14 : }
|