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 : #include "zarr.h"
30 :
31 : #include <algorithm>
32 : #include <cassert>
33 : #include <map>
34 :
35 : constexpr const char *ATTRIBUTE_GROUP_SUFFIX = "/_GLOBAL_";
36 :
37 : /************************************************************************/
38 : /* ZarrAttributeGroup::ZarrAttributeGroup() */
39 : /************************************************************************/
40 :
41 2556 : ZarrAttributeGroup::ZarrAttributeGroup(const std::string &osParentName,
42 2556 : bool bContainerIsGroup)
43 : : m_bContainerIsGroup(bContainerIsGroup),
44 : m_poGroup(MEMGroup::Create(
45 : bContainerIsGroup
46 5112 : ? (osParentName == "/" ? ATTRIBUTE_GROUP_SUFFIX
47 : : osParentName + ATTRIBUTE_GROUP_SUFFIX)
48 : : osParentName,
49 5112 : nullptr))
50 : {
51 2556 : }
52 :
53 : /************************************************************************/
54 : /* ZarrAttributeGroup::Init() */
55 : /************************************************************************/
56 :
57 794 : void ZarrAttributeGroup::Init(const CPLJSONObject &obj, bool bUpdatable)
58 : {
59 794 : if (obj.GetType() != CPLJSONObject::Type::Object)
60 28 : return;
61 1532 : const auto children = obj.GetChildren();
62 1067 : for (const auto &item : children)
63 : {
64 301 : const auto itemType = item.GetType();
65 301 : bool bDone = false;
66 301 : std::shared_ptr<GDALAttribute> poAttr;
67 301 : if (itemType == CPLJSONObject::Type::String)
68 : {
69 183 : bDone = true;
70 732 : poAttr = m_poGroup->CreateAttribute(
71 366 : item.GetName(), {}, GDALExtendedDataType::CreateString(),
72 366 : nullptr);
73 183 : if (poAttr)
74 : {
75 183 : const GUInt64 arrayStartIdx = 0;
76 183 : const size_t count = 1;
77 183 : const GInt64 arrayStep = 0;
78 183 : const GPtrDiff_t bufferStride = 0;
79 549 : const std::string str = item.ToString();
80 183 : const char *c_str = str.c_str();
81 366 : poAttr->Write(&arrayStartIdx, &count, &arrayStep, &bufferStride,
82 183 : poAttr->GetDataType(), &c_str);
83 : }
84 : }
85 118 : else if (itemType == CPLJSONObject::Type::Integer ||
86 96 : itemType == CPLJSONObject::Type::Long ||
87 : itemType == CPLJSONObject::Type::Double)
88 : {
89 57 : bDone = true;
90 228 : poAttr = m_poGroup->CreateAttribute(
91 114 : item.GetName(), {},
92 114 : GDALExtendedDataType::Create(
93 : itemType == CPLJSONObject::Type::Integer ? GDT_Int32
94 : : GDT_Float64),
95 114 : nullptr);
96 57 : if (poAttr)
97 : {
98 57 : const GUInt64 arrayStartIdx = 0;
99 57 : const size_t count = 1;
100 57 : const GInt64 arrayStep = 0;
101 57 : const GPtrDiff_t bufferStride = 0;
102 57 : const double val = item.ToDouble();
103 114 : poAttr->Write(&arrayStartIdx, &count, &arrayStep, &bufferStride,
104 114 : GDALExtendedDataType::Create(GDT_Float64), &val);
105 57 : }
106 : }
107 61 : else if (itemType == CPLJSONObject::Type::Array)
108 : {
109 70 : const auto array = item.ToArray();
110 35 : bool isFirst = true;
111 35 : bool isString = false;
112 35 : bool isNumeric = false;
113 35 : bool foundInt64 = false;
114 35 : bool foundDouble = false;
115 35 : bool mixedType = false;
116 35 : size_t countItems = 0;
117 107 : for (const auto &subItem : array)
118 : {
119 72 : const auto subItemType = subItem.GetType();
120 72 : if (subItemType == CPLJSONObject::Type::String)
121 : {
122 24 : if (isFirst)
123 : {
124 12 : isString = true;
125 : }
126 12 : else if (!isString)
127 : {
128 0 : mixedType = true;
129 0 : break;
130 : }
131 24 : countItems++;
132 : }
133 48 : else if (subItemType == CPLJSONObject::Type::Integer ||
134 20 : subItemType == CPLJSONObject::Type::Long ||
135 : subItemType == CPLJSONObject::Type::Double)
136 : {
137 48 : if (isFirst)
138 : {
139 23 : isNumeric = true;
140 : }
141 25 : else if (!isNumeric)
142 : {
143 2 : mixedType = true;
144 2 : break;
145 : }
146 46 : if (subItemType == CPLJSONObject::Type::Double)
147 20 : foundDouble = true;
148 26 : else if (subItemType == CPLJSONObject::Type::Long)
149 4 : foundInt64 = true;
150 46 : countItems++;
151 : }
152 : else
153 : {
154 0 : mixedType = true;
155 0 : break;
156 : }
157 70 : isFirst = false;
158 : }
159 :
160 35 : if (!mixedType && !isFirst)
161 : {
162 33 : bDone = true;
163 165 : poAttr = m_poGroup->CreateAttribute(
164 66 : item.GetName(), {countItems},
165 78 : isString ? GDALExtendedDataType::CreateString()
166 : : GDALExtendedDataType::Create(
167 12 : (foundDouble || foundInt64) ? GDT_Float64
168 : : GDT_Int32),
169 66 : nullptr);
170 33 : if (poAttr)
171 : {
172 33 : size_t idx = 0;
173 101 : for (const auto &subItem : array)
174 : {
175 68 : const GUInt64 arrayStartIdx = idx;
176 68 : const size_t count = 1;
177 68 : const GInt64 arrayStep = 0;
178 68 : const GPtrDiff_t bufferStride = 0;
179 68 : const auto subItemType = subItem.GetType();
180 68 : if (subItemType == CPLJSONObject::Type::String)
181 : {
182 66 : const std::string str = subItem.ToString();
183 22 : const char *c_str = str.c_str();
184 44 : poAttr->Write(&arrayStartIdx, &count, &arrayStep,
185 22 : &bufferStride, poAttr->GetDataType(),
186 : &c_str);
187 : }
188 46 : else if (subItemType == CPLJSONObject::Type::Integer ||
189 20 : subItemType == CPLJSONObject::Type::Long ||
190 : subItemType == CPLJSONObject::Type::Double)
191 : {
192 46 : const double val = subItem.ToDouble();
193 92 : poAttr->Write(
194 : &arrayStartIdx, &count, &arrayStep,
195 : &bufferStride,
196 92 : GDALExtendedDataType::Create(GDT_Float64),
197 : &val);
198 : }
199 68 : ++idx;
200 : }
201 : }
202 : }
203 : }
204 :
205 301 : if (!bDone)
206 : {
207 28 : constexpr size_t nMaxStringLength = 0;
208 : const auto eDT = GDALExtendedDataType::CreateString(
209 56 : nMaxStringLength, GEDTST_JSON);
210 : poAttr =
211 28 : m_poGroup->CreateAttribute(item.GetName(), {}, eDT, nullptr);
212 28 : if (poAttr)
213 : {
214 28 : const GUInt64 arrayStartIdx = 0;
215 28 : const size_t count = 1;
216 28 : const GInt64 arrayStep = 0;
217 28 : const GPtrDiff_t bufferStride = 0;
218 84 : const std::string str = item.ToString();
219 28 : const char *c_str = str.c_str();
220 56 : poAttr->Write(&arrayStartIdx, &count, &arrayStep, &bufferStride,
221 28 : poAttr->GetDataType(), &c_str);
222 : }
223 : }
224 :
225 602 : auto poMemAttr = std::dynamic_pointer_cast<MEMAttribute>(poAttr);
226 301 : if (poMemAttr)
227 301 : poMemAttr->SetModified(false);
228 : }
229 766 : SetUpdatable(bUpdatable);
230 : }
231 :
232 : /************************************************************************/
233 : /* ZarrAttributeGroup::Serialize() */
234 : /************************************************************************/
235 :
236 431 : CPLJSONObject ZarrAttributeGroup::Serialize() const
237 : {
238 431 : CPLJSONObject o;
239 862 : const auto attrs = m_poGroup->GetAttributes(nullptr);
240 637 : for (const auto &attr : attrs)
241 : {
242 206 : const auto &oType = attr->GetDataType();
243 206 : if (oType.GetClass() == GEDTC_STRING)
244 : {
245 320 : const auto anDims = attr->GetDimensionsSize();
246 160 : if (anDims.size() == 0)
247 : {
248 152 : const char *pszStr = attr->ReadAsString();
249 152 : if (pszStr)
250 : {
251 304 : CPLJSONDocument oDoc;
252 158 : if (oType.GetSubType() == GEDTST_JSON &&
253 158 : oDoc.LoadMemory(pszStr))
254 : {
255 6 : o.Add(attr->GetName(), oDoc.GetRoot());
256 : }
257 : else
258 : {
259 146 : o.Add(attr->GetName(), pszStr);
260 : }
261 : }
262 : else
263 : {
264 0 : o.AddNull(attr->GetName());
265 : }
266 : }
267 8 : else if (anDims.size() == 1)
268 : {
269 16 : const auto list = attr->ReadAsStringArray();
270 16 : CPLJSONArray arr;
271 26 : for (int i = 0; i < list.size(); ++i)
272 : {
273 18 : arr.Add(list[i]);
274 : }
275 8 : o.Add(attr->GetName(), arr);
276 : }
277 : else
278 : {
279 0 : CPLError(
280 : CE_Warning, CPLE_AppDefined,
281 : "Cannot serialize attribute %s of dimension count >= 2",
282 0 : attr->GetName().c_str());
283 : }
284 : }
285 46 : else if (oType.GetClass() == GEDTC_NUMERIC)
286 : {
287 92 : const auto anDims = attr->GetDimensionsSize();
288 46 : const auto eDT = oType.GetNumericDataType();
289 46 : if (anDims.size() == 0)
290 : {
291 33 : const double dfVal = attr->ReadAsDouble();
292 33 : if (eDT == GDT_Byte || eDT == GDT_UInt16 || eDT == GDT_UInt32 ||
293 15 : eDT == GDT_Int16 || eDT == GDT_Int32)
294 : {
295 24 : o.Add(attr->GetName(), static_cast<GInt64>(dfVal));
296 : }
297 : else
298 : {
299 9 : o.Add(attr->GetName(), dfVal);
300 : }
301 : }
302 13 : else if (anDims.size() == 1)
303 : {
304 26 : const auto list = attr->ReadAsDoubleArray();
305 26 : CPLJSONArray arr;
306 39 : for (const auto dfVal : list)
307 : {
308 26 : if (eDT == GDT_Byte || eDT == GDT_UInt16 ||
309 26 : eDT == GDT_UInt32 || eDT == GDT_Int16 ||
310 : eDT == GDT_Int32)
311 : {
312 12 : arr.Add(static_cast<GInt64>(dfVal));
313 : }
314 : else
315 : {
316 14 : arr.Add(dfVal);
317 : }
318 : }
319 13 : o.Add(attr->GetName(), arr);
320 : }
321 : else
322 : {
323 0 : CPLError(
324 : CE_Warning, CPLE_AppDefined,
325 : "Cannot serialize attribute %s of dimension count >= 2",
326 0 : attr->GetName().c_str());
327 : }
328 : }
329 : }
330 862 : return o;
331 : }
332 :
333 : /************************************************************************/
334 : /* ParentRenamed() */
335 : /************************************************************************/
336 :
337 25 : void ZarrAttributeGroup::ParentRenamed(const std::string &osNewParentFullName)
338 : {
339 25 : if (m_bContainerIsGroup)
340 10 : m_poGroup->SetFullName(osNewParentFullName + ATTRIBUTE_GROUP_SUFFIX);
341 : else
342 15 : m_poGroup->SetFullName(osNewParentFullName);
343 50 : const auto attrs = m_poGroup->GetAttributes(nullptr);
344 52 : for (auto &attr : attrs)
345 : {
346 27 : attr->ParentRenamed(m_poGroup->GetFullName());
347 : }
348 25 : }
349 :
350 : /************************************************************************/
351 : /* ParentDeleted() */
352 : /************************************************************************/
353 :
354 14 : void ZarrAttributeGroup::ParentDeleted()
355 : {
356 14 : m_poGroup->Deleted();
357 14 : }
|