/src/gdal/frmts/mem/memdataset.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: Memory Array Translator |
4 | | * Purpose: Complete implementation. |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2000, Frank Warmerdam |
9 | | * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "cpl_port.h" |
15 | | #include "memdataset.h" |
16 | | #include "memmultidim.h" |
17 | | |
18 | | #include <algorithm> |
19 | | #include <climits> |
20 | | #include <cstdlib> |
21 | | #include <cstring> |
22 | | #include <limits> |
23 | | #include <vector> |
24 | | |
25 | | #include "cpl_config.h" |
26 | | #include "cpl_conv.h" |
27 | | #include "cpl_error.h" |
28 | | #include "cpl_minixml.h" |
29 | | #include "cpl_progress.h" |
30 | | #include "cpl_string.h" |
31 | | #include "cpl_vsi.h" |
32 | | #include "gdal.h" |
33 | | #include "gdal_frmts.h" |
34 | | |
35 | | struct MEMDataset::Private |
36 | | { |
37 | | std::shared_ptr<GDALGroup> m_poRootGroup{}; |
38 | | }; |
39 | | |
40 | | /************************************************************************/ |
41 | | /* MEMCreateRasterBand() */ |
42 | | /************************************************************************/ |
43 | | |
44 | | GDALRasterBandH MEMCreateRasterBand(GDALDataset *poDS, int nBand, |
45 | | GByte *pabyData, GDALDataType eType, |
46 | | int nPixelOffset, int nLineOffset, |
47 | | int bAssumeOwnership) |
48 | | |
49 | 0 | { |
50 | 0 | return GDALRasterBand::ToHandle( |
51 | 0 | new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset, |
52 | 0 | nLineOffset, bAssumeOwnership)); |
53 | 0 | } |
54 | | |
55 | | /************************************************************************/ |
56 | | /* MEMCreateRasterBandEx() */ |
57 | | /************************************************************************/ |
58 | | |
59 | | GDALRasterBandH MEMCreateRasterBandEx(GDALDataset *poDS, int nBand, |
60 | | GByte *pabyData, GDALDataType eType, |
61 | | GSpacing nPixelOffset, |
62 | | GSpacing nLineOffset, |
63 | | int bAssumeOwnership) |
64 | | |
65 | 0 | { |
66 | 0 | return GDALRasterBand::ToHandle( |
67 | 0 | new MEMRasterBand(poDS, nBand, pabyData, eType, nPixelOffset, |
68 | 0 | nLineOffset, bAssumeOwnership)); |
69 | 0 | } |
70 | | |
71 | | /************************************************************************/ |
72 | | /* MEMRasterBand() */ |
73 | | /************************************************************************/ |
74 | | |
75 | | MEMRasterBand::MEMRasterBand(GByte *pabyDataIn, GDALDataType eTypeIn, |
76 | | int nXSizeIn, int nYSizeIn, bool bOwnDataIn) |
77 | 0 | : GDALPamRasterBand(FALSE), pabyData(pabyDataIn), |
78 | 0 | nPixelOffset(GDALGetDataTypeSizeBytes(eTypeIn)), nLineOffset(0), |
79 | 0 | bOwnData(bOwnDataIn) |
80 | 0 | { |
81 | 0 | eAccess = GA_Update; |
82 | 0 | eDataType = eTypeIn; |
83 | 0 | nRasterXSize = nXSizeIn; |
84 | 0 | nRasterYSize = nYSizeIn; |
85 | 0 | nBlockXSize = nXSizeIn; |
86 | 0 | nBlockYSize = 1; |
87 | 0 | nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize); |
88 | |
|
89 | 0 | PamInitializeNoParent(); |
90 | 0 | } |
91 | | |
92 | | /************************************************************************/ |
93 | | /* MEMRasterBand() */ |
94 | | /************************************************************************/ |
95 | | |
96 | | MEMRasterBand::MEMRasterBand(GDALDataset *poDSIn, int nBandIn, |
97 | | GByte *pabyDataIn, GDALDataType eTypeIn, |
98 | | GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn, |
99 | | int bAssumeOwnership, const char *pszPixelType) |
100 | 0 | : GDALPamRasterBand(FALSE), pabyData(pabyDataIn), |
101 | 0 | nPixelOffset(nPixelOffsetIn), nLineOffset(nLineOffsetIn), |
102 | 0 | bOwnData(bAssumeOwnership) |
103 | 0 | { |
104 | 0 | poDS = poDSIn; |
105 | 0 | nBand = nBandIn; |
106 | |
|
107 | 0 | eAccess = poDS->GetAccess(); |
108 | |
|
109 | 0 | eDataType = eTypeIn; |
110 | |
|
111 | 0 | nBlockXSize = poDS->GetRasterXSize(); |
112 | 0 | nBlockYSize = 1; |
113 | |
|
114 | 0 | if (nPixelOffsetIn == 0) |
115 | 0 | nPixelOffset = GDALGetDataTypeSizeBytes(eTypeIn); |
116 | |
|
117 | 0 | if (nLineOffsetIn == 0) |
118 | 0 | nLineOffset = nPixelOffset * static_cast<size_t>(nBlockXSize); |
119 | |
|
120 | 0 | if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE")) |
121 | 0 | SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE"); |
122 | |
|
123 | 0 | PamInitializeNoParent(); |
124 | 0 | } |
125 | | |
126 | | /************************************************************************/ |
127 | | /* ~MEMRasterBand() */ |
128 | | /************************************************************************/ |
129 | | |
130 | | MEMRasterBand::~MEMRasterBand() |
131 | | |
132 | 0 | { |
133 | 0 | if (bOwnData) |
134 | 0 | { |
135 | 0 | VSIFree(pabyData); |
136 | 0 | } |
137 | 0 | } |
138 | | |
139 | | /************************************************************************/ |
140 | | /* IReadBlock() */ |
141 | | /************************************************************************/ |
142 | | |
143 | | CPLErr MEMRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, |
144 | | void *pImage) |
145 | 0 | { |
146 | 0 | CPLAssert(nBlockXOff == 0); |
147 | | |
148 | 0 | const int nWordSize = GDALGetDataTypeSize(eDataType) / 8; |
149 | |
|
150 | 0 | if (nPixelOffset == nWordSize) |
151 | 0 | { |
152 | 0 | memcpy(pImage, pabyData + nLineOffset * static_cast<size_t>(nBlockYOff), |
153 | 0 | static_cast<size_t>(nPixelOffset) * nBlockXSize); |
154 | 0 | } |
155 | 0 | else |
156 | 0 | { |
157 | 0 | GByte *const pabyCur = |
158 | 0 | pabyData + nLineOffset * static_cast<size_t>(nBlockYOff); |
159 | |
|
160 | 0 | for (int iPixel = 0; iPixel < nBlockXSize; iPixel++) |
161 | 0 | { |
162 | 0 | memcpy(static_cast<GByte *>(pImage) + iPixel * nWordSize, |
163 | 0 | pabyCur + iPixel * nPixelOffset, nWordSize); |
164 | 0 | } |
165 | 0 | } |
166 | |
|
167 | 0 | return CE_None; |
168 | 0 | } |
169 | | |
170 | | /************************************************************************/ |
171 | | /* IWriteBlock() */ |
172 | | /************************************************************************/ |
173 | | |
174 | | CPLErr MEMRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, |
175 | | void *pImage) |
176 | 0 | { |
177 | 0 | CPLAssert(nBlockXOff == 0); |
178 | 0 | const int nWordSize = GDALGetDataTypeSize(eDataType) / 8; |
179 | |
|
180 | 0 | if (nPixelOffset == nWordSize) |
181 | 0 | { |
182 | 0 | memcpy(pabyData + nLineOffset * static_cast<size_t>(nBlockYOff), pImage, |
183 | 0 | static_cast<size_t>(nPixelOffset) * nBlockXSize); |
184 | 0 | } |
185 | 0 | else |
186 | 0 | { |
187 | 0 | GByte *pabyCur = |
188 | 0 | pabyData + nLineOffset * static_cast<size_t>(nBlockYOff); |
189 | |
|
190 | 0 | for (int iPixel = 0; iPixel < nBlockXSize; iPixel++) |
191 | 0 | { |
192 | 0 | memcpy(pabyCur + iPixel * nPixelOffset, |
193 | 0 | static_cast<GByte *>(pImage) + iPixel * nWordSize, |
194 | 0 | nWordSize); |
195 | 0 | } |
196 | 0 | } |
197 | |
|
198 | 0 | return CE_None; |
199 | 0 | } |
200 | | |
201 | | /************************************************************************/ |
202 | | /* IRasterIO() */ |
203 | | /************************************************************************/ |
204 | | |
205 | | CPLErr MEMRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, |
206 | | int nXSize, int nYSize, void *pData, |
207 | | int nBufXSize, int nBufYSize, |
208 | | GDALDataType eBufType, GSpacing nPixelSpaceBuf, |
209 | | GSpacing nLineSpaceBuf, |
210 | | GDALRasterIOExtraArg *psExtraArg) |
211 | 0 | { |
212 | 0 | if (nXSize != nBufXSize || nYSize != nBufYSize) |
213 | 0 | { |
214 | 0 | return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, |
215 | 0 | pData, nBufXSize, nBufYSize, eBufType, |
216 | 0 | static_cast<int>(nPixelSpaceBuf), |
217 | 0 | nLineSpaceBuf, psExtraArg); |
218 | 0 | } |
219 | | |
220 | | // In case block based I/O has been done before. |
221 | 0 | FlushCache(false); |
222 | |
|
223 | 0 | if (eRWFlag == GF_Read) |
224 | 0 | { |
225 | 0 | for (int iLine = 0; iLine < nYSize; iLine++) |
226 | 0 | { |
227 | 0 | GDALCopyWords(pabyData + |
228 | 0 | nLineOffset * |
229 | 0 | static_cast<GPtrDiff_t>(iLine + nYOff) + |
230 | 0 | nXOff * nPixelOffset, |
231 | 0 | eDataType, static_cast<int>(nPixelOffset), |
232 | 0 | static_cast<GByte *>(pData) + |
233 | 0 | nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine), |
234 | 0 | eBufType, static_cast<int>(nPixelSpaceBuf), nXSize); |
235 | 0 | } |
236 | 0 | } |
237 | 0 | else |
238 | 0 | { |
239 | 0 | for (int iLine = 0; iLine < nYSize; iLine++) |
240 | 0 | { |
241 | 0 | GDALCopyWords(static_cast<GByte *>(pData) + |
242 | 0 | nLineSpaceBuf * static_cast<GPtrDiff_t>(iLine), |
243 | 0 | eBufType, static_cast<int>(nPixelSpaceBuf), |
244 | 0 | pabyData + |
245 | 0 | nLineOffset * |
246 | 0 | static_cast<GPtrDiff_t>(iLine + nYOff) + |
247 | 0 | nXOff * nPixelOffset, |
248 | 0 | eDataType, static_cast<int>(nPixelOffset), nXSize); |
249 | 0 | } |
250 | 0 | } |
251 | 0 | return CE_None; |
252 | 0 | } |
253 | | |
254 | | /************************************************************************/ |
255 | | /* IRasterIO() */ |
256 | | /************************************************************************/ |
257 | | |
258 | | CPLErr MEMDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, |
259 | | int nXSize, int nYSize, void *pData, int nBufXSize, |
260 | | int nBufYSize, GDALDataType eBufType, |
261 | | int nBandCount, BANDMAP_TYPE panBandMap, |
262 | | GSpacing nPixelSpaceBuf, GSpacing nLineSpaceBuf, |
263 | | GSpacing nBandSpaceBuf, |
264 | | GDALRasterIOExtraArg *psExtraArg) |
265 | 0 | { |
266 | 0 | const int eBufTypeSize = GDALGetDataTypeSize(eBufType) / 8; |
267 | | |
268 | | // Detect if we have a pixel-interleaved buffer |
269 | 0 | if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount == nBands && |
270 | 0 | nBands > 1 && nBandSpaceBuf == eBufTypeSize && |
271 | 0 | nPixelSpaceBuf == nBandSpaceBuf * nBands) |
272 | 0 | { |
273 | 0 | const auto IsPixelInterleaveDataset = [this, nBandCount, panBandMap]() |
274 | 0 | { |
275 | 0 | GDALDataType eDT = GDT_Unknown; |
276 | 0 | GByte *pabyData = nullptr; |
277 | 0 | GSpacing nPixelOffset = 0; |
278 | 0 | GSpacing nLineOffset = 0; |
279 | 0 | int eDTSize = 0; |
280 | 0 | for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++) |
281 | 0 | { |
282 | 0 | if (panBandMap[iBandIndex] != iBandIndex + 1) |
283 | 0 | return false; |
284 | | |
285 | 0 | MEMRasterBand *poBand = cpl::down_cast<MEMRasterBand *>( |
286 | 0 | GetRasterBand(iBandIndex + 1)); |
287 | 0 | if (iBandIndex == 0) |
288 | 0 | { |
289 | 0 | eDT = poBand->GetRasterDataType(); |
290 | 0 | pabyData = poBand->pabyData; |
291 | 0 | nPixelOffset = poBand->nPixelOffset; |
292 | 0 | nLineOffset = poBand->nLineOffset; |
293 | 0 | eDTSize = GDALGetDataTypeSizeBytes(eDT); |
294 | 0 | if (nPixelOffset != static_cast<GSpacing>(nBands) * eDTSize) |
295 | 0 | return false; |
296 | 0 | } |
297 | 0 | else if (poBand->GetRasterDataType() != eDT || |
298 | 0 | nPixelOffset != poBand->nPixelOffset || |
299 | 0 | nLineOffset != poBand->nLineOffset || |
300 | 0 | poBand->pabyData != pabyData + iBandIndex * eDTSize) |
301 | 0 | { |
302 | 0 | return false; |
303 | 0 | } |
304 | 0 | } |
305 | 0 | return true; |
306 | 0 | }; |
307 | |
|
308 | 0 | const auto IsBandSeparatedDataset = [this, nBandCount, panBandMap]() |
309 | 0 | { |
310 | 0 | GDALDataType eDT = GDT_Unknown; |
311 | 0 | GSpacing nPixelOffset = 0; |
312 | 0 | GSpacing nLineOffset = 0; |
313 | 0 | int eDTSize = 0; |
314 | 0 | for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++) |
315 | 0 | { |
316 | 0 | if (panBandMap[iBandIndex] != iBandIndex + 1) |
317 | 0 | return false; |
318 | | |
319 | 0 | MEMRasterBand *poBand = cpl::down_cast<MEMRasterBand *>( |
320 | 0 | GetRasterBand(iBandIndex + 1)); |
321 | 0 | if (iBandIndex == 0) |
322 | 0 | { |
323 | 0 | eDT = poBand->GetRasterDataType(); |
324 | 0 | nPixelOffset = poBand->nPixelOffset; |
325 | 0 | nLineOffset = poBand->nLineOffset; |
326 | 0 | eDTSize = GDALGetDataTypeSizeBytes(eDT); |
327 | 0 | if (nPixelOffset != eDTSize) |
328 | 0 | return false; |
329 | 0 | } |
330 | 0 | else if (poBand->GetRasterDataType() != eDT || |
331 | 0 | nPixelOffset != poBand->nPixelOffset || |
332 | 0 | nLineOffset != poBand->nLineOffset) |
333 | 0 | { |
334 | 0 | return false; |
335 | 0 | } |
336 | 0 | } |
337 | 0 | return true; |
338 | 0 | }; |
339 | |
|
340 | 0 | if (IsPixelInterleaveDataset()) |
341 | 0 | { |
342 | 0 | FlushCache(false); |
343 | 0 | const auto poFirstBand = |
344 | 0 | cpl::down_cast<MEMRasterBand *>(papoBands[0]); |
345 | 0 | const GDALDataType eDT = poFirstBand->GetRasterDataType(); |
346 | 0 | GByte *pabyData = poFirstBand->pabyData; |
347 | 0 | const GSpacing nPixelOffset = poFirstBand->nPixelOffset; |
348 | 0 | const GSpacing nLineOffset = poFirstBand->nLineOffset; |
349 | 0 | const int eDTSize = GDALGetDataTypeSizeBytes(eDT); |
350 | 0 | if (eRWFlag == GF_Read) |
351 | 0 | { |
352 | 0 | for (int iLine = 0; iLine < nYSize; iLine++) |
353 | 0 | { |
354 | 0 | GDALCopyWords( |
355 | 0 | pabyData + |
356 | 0 | nLineOffset * static_cast<size_t>(iLine + nYOff) + |
357 | 0 | nXOff * nPixelOffset, |
358 | 0 | eDT, eDTSize, |
359 | 0 | static_cast<GByte *>(pData) + |
360 | 0 | nLineSpaceBuf * static_cast<size_t>(iLine), |
361 | 0 | eBufType, eBufTypeSize, nXSize * nBands); |
362 | 0 | } |
363 | 0 | } |
364 | 0 | else |
365 | 0 | { |
366 | 0 | for (int iLine = 0; iLine < nYSize; iLine++) |
367 | 0 | { |
368 | 0 | GDALCopyWords( |
369 | 0 | static_cast<GByte *>(pData) + |
370 | 0 | nLineSpaceBuf * static_cast<size_t>(iLine), |
371 | 0 | eBufType, eBufTypeSize, |
372 | 0 | pabyData + |
373 | 0 | nLineOffset * static_cast<size_t>(iLine + nYOff) + |
374 | 0 | nXOff * nPixelOffset, |
375 | 0 | eDT, eDTSize, nXSize * nBands); |
376 | 0 | } |
377 | 0 | } |
378 | 0 | return CE_None; |
379 | 0 | } |
380 | 0 | else if (eRWFlag == GF_Write && nBandCount <= 4 && |
381 | 0 | IsBandSeparatedDataset()) |
382 | 0 | { |
383 | | // TODO: once we have a GDALInterleave() function, implement the |
384 | | // GF_Read case |
385 | 0 | FlushCache(false); |
386 | 0 | const auto poFirstBand = |
387 | 0 | cpl::down_cast<MEMRasterBand *>(papoBands[0]); |
388 | 0 | const GDALDataType eDT = poFirstBand->GetRasterDataType(); |
389 | 0 | void *ppDestBuffer[4] = {nullptr, nullptr, nullptr, nullptr}; |
390 | 0 | if (nXOff == 0 && nXSize == nRasterXSize && |
391 | 0 | poFirstBand->nLineOffset == |
392 | 0 | poFirstBand->nPixelOffset * nXSize && |
393 | 0 | nLineSpaceBuf == nPixelSpaceBuf * nXSize) |
394 | 0 | { |
395 | | // Optimization of the general case in the below else() clause: |
396 | | // writing whole strips from a fully packed buffer |
397 | 0 | for (int i = 0; i < nBandCount; ++i) |
398 | 0 | { |
399 | 0 | const auto poBand = |
400 | 0 | cpl::down_cast<MEMRasterBand *>(papoBands[i]); |
401 | 0 | ppDestBuffer[i] = |
402 | 0 | poBand->pabyData + poBand->nLineOffset * nYOff; |
403 | 0 | } |
404 | 0 | GDALDeinterleave(pData, eBufType, nBandCount, ppDestBuffer, eDT, |
405 | 0 | static_cast<size_t>(nXSize) * nYSize); |
406 | 0 | } |
407 | 0 | else |
408 | 0 | { |
409 | 0 | for (int iLine = 0; iLine < nYSize; iLine++) |
410 | 0 | { |
411 | 0 | for (int i = 0; i < nBandCount; ++i) |
412 | 0 | { |
413 | 0 | const auto poBand = |
414 | 0 | cpl::down_cast<MEMRasterBand *>(papoBands[i]); |
415 | 0 | ppDestBuffer[i] = poBand->pabyData + |
416 | 0 | poBand->nPixelOffset * nXOff + |
417 | 0 | poBand->nLineOffset * (iLine + nYOff); |
418 | 0 | } |
419 | 0 | GDALDeinterleave( |
420 | 0 | static_cast<GByte *>(pData) + |
421 | 0 | nLineSpaceBuf * static_cast<size_t>(iLine), |
422 | 0 | eBufType, nBandCount, ppDestBuffer, eDT, nXSize); |
423 | 0 | } |
424 | 0 | } |
425 | 0 | return CE_None; |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | 0 | if (nBufXSize != nXSize || nBufYSize != nYSize) |
430 | 0 | return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, |
431 | 0 | pData, nBufXSize, nBufYSize, eBufType, |
432 | 0 | nBandCount, panBandMap, nPixelSpaceBuf, |
433 | 0 | nLineSpaceBuf, nBandSpaceBuf, psExtraArg); |
434 | | |
435 | 0 | return GDALDataset::BandBasedRasterIO( |
436 | 0 | eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, |
437 | 0 | eBufType, nBandCount, panBandMap, nPixelSpaceBuf, nLineSpaceBuf, |
438 | 0 | nBandSpaceBuf, psExtraArg); |
439 | 0 | } |
440 | | |
441 | | /************************************************************************/ |
442 | | /* GetOverviewCount() */ |
443 | | /************************************************************************/ |
444 | | |
445 | | int MEMRasterBand::GetOverviewCount() |
446 | 0 | { |
447 | 0 | MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS); |
448 | 0 | if (poMemDS == nullptr) |
449 | 0 | return 0; |
450 | 0 | return static_cast<int>(poMemDS->m_apoOverviewDS.size()); |
451 | 0 | } |
452 | | |
453 | | /************************************************************************/ |
454 | | /* GetOverview() */ |
455 | | /************************************************************************/ |
456 | | |
457 | | GDALRasterBand *MEMRasterBand::GetOverview(int i) |
458 | | |
459 | 0 | { |
460 | 0 | MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS); |
461 | 0 | if (poMemDS == nullptr) |
462 | 0 | return nullptr; |
463 | 0 | if (i < 0 || i >= static_cast<int>(poMemDS->m_apoOverviewDS.size())) |
464 | 0 | return nullptr; |
465 | 0 | return poMemDS->m_apoOverviewDS[i]->GetRasterBand(nBand); |
466 | 0 | } |
467 | | |
468 | | /************************************************************************/ |
469 | | /* CreateMaskBand() */ |
470 | | /************************************************************************/ |
471 | | |
472 | | CPLErr MEMRasterBand::CreateMaskBand(int nFlagsIn) |
473 | 0 | { |
474 | 0 | InvalidateMaskBand(); |
475 | |
|
476 | 0 | MEMDataset *poMemDS = dynamic_cast<MEMDataset *>(poDS); |
477 | 0 | if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand != 1 && poMemDS != nullptr) |
478 | 0 | { |
479 | 0 | MEMRasterBand *poFirstBand = |
480 | 0 | dynamic_cast<MEMRasterBand *>(poMemDS->GetRasterBand(1)); |
481 | 0 | if (poFirstBand != nullptr) |
482 | 0 | return poFirstBand->CreateMaskBand(nFlagsIn); |
483 | 0 | } |
484 | | |
485 | 0 | GByte *pabyMaskData = |
486 | 0 | static_cast<GByte *>(VSI_CALLOC_VERBOSE(nRasterXSize, nRasterYSize)); |
487 | 0 | if (pabyMaskData == nullptr) |
488 | 0 | return CE_Failure; |
489 | | |
490 | 0 | nMaskFlags = nFlagsIn; |
491 | 0 | auto poMemMaskBand = new MEMRasterBand(pabyMaskData, GDT_Byte, nRasterXSize, |
492 | 0 | nRasterYSize, /* bOwnData= */ true); |
493 | 0 | poMemMaskBand->m_bIsMask = true; |
494 | 0 | poMask.reset(poMemMaskBand, true); |
495 | 0 | if ((nFlagsIn & GMF_PER_DATASET) != 0 && nBand == 1 && poMemDS != nullptr) |
496 | 0 | { |
497 | 0 | for (int i = 2; i <= poMemDS->GetRasterCount(); ++i) |
498 | 0 | { |
499 | 0 | MEMRasterBand *poOtherBand = |
500 | 0 | cpl::down_cast<MEMRasterBand *>(poMemDS->GetRasterBand(i)); |
501 | 0 | poOtherBand->InvalidateMaskBand(); |
502 | 0 | poOtherBand->nMaskFlags = nFlagsIn; |
503 | 0 | poOtherBand->poMask.reset(poMask.get(), false); |
504 | 0 | } |
505 | 0 | } |
506 | 0 | return CE_None; |
507 | 0 | } |
508 | | |
509 | | /************************************************************************/ |
510 | | /* IsMaskBand() */ |
511 | | /************************************************************************/ |
512 | | |
513 | | bool MEMRasterBand::IsMaskBand() const |
514 | 0 | { |
515 | 0 | return m_bIsMask || GDALPamRasterBand::IsMaskBand(); |
516 | 0 | } |
517 | | |
518 | | /************************************************************************/ |
519 | | /* ==================================================================== */ |
520 | | /* MEMDataset */ |
521 | | /* ==================================================================== */ |
522 | | /************************************************************************/ |
523 | | |
524 | | /************************************************************************/ |
525 | | /* MEMDataset() */ |
526 | | /************************************************************************/ |
527 | | |
528 | | MEMDataset::MEMDataset() |
529 | 0 | : GDALDataset(FALSE), bGeoTransformSet(FALSE), m_poPrivate(new Private()) |
530 | 0 | { |
531 | 0 | adfGeoTransform[0] = 0.0; |
532 | 0 | adfGeoTransform[1] = 1.0; |
533 | 0 | adfGeoTransform[2] = 0.0; |
534 | 0 | adfGeoTransform[3] = 0.0; |
535 | 0 | adfGeoTransform[4] = 0.0; |
536 | 0 | adfGeoTransform[5] = -1.0; |
537 | 0 | DisableReadWriteMutex(); |
538 | 0 | } |
539 | | |
540 | | /************************************************************************/ |
541 | | /* ~MEMDataset() */ |
542 | | /************************************************************************/ |
543 | | |
544 | | MEMDataset::~MEMDataset() |
545 | | |
546 | 0 | { |
547 | 0 | const bool bSuppressOnCloseBackup = bSuppressOnClose; |
548 | 0 | bSuppressOnClose = true; |
549 | 0 | FlushCache(true); |
550 | 0 | bSuppressOnClose = bSuppressOnCloseBackup; |
551 | 0 | } |
552 | | |
553 | | #if 0 |
554 | | /************************************************************************/ |
555 | | /* EnterReadWrite() */ |
556 | | /************************************************************************/ |
557 | | |
558 | | int MEMDataset::EnterReadWrite(CPL_UNUSED GDALRWFlag eRWFlag) |
559 | | { |
560 | | return TRUE; |
561 | | } |
562 | | |
563 | | /************************************************************************/ |
564 | | /* LeaveReadWrite() */ |
565 | | /************************************************************************/ |
566 | | |
567 | | void MEMDataset::LeaveReadWrite() |
568 | | { |
569 | | } |
570 | | #endif // if 0 |
571 | | |
572 | | /************************************************************************/ |
573 | | /* GetSpatialRef() */ |
574 | | /************************************************************************/ |
575 | | |
576 | | const OGRSpatialReference *MEMDataset::GetSpatialRef() const |
577 | | |
578 | 0 | { |
579 | 0 | return m_oSRS.IsEmpty() ? nullptr : &m_oSRS; |
580 | 0 | } |
581 | | |
582 | | /************************************************************************/ |
583 | | /* SetSpatialRef() */ |
584 | | /************************************************************************/ |
585 | | |
586 | | CPLErr MEMDataset::SetSpatialRef(const OGRSpatialReference *poSRS) |
587 | | |
588 | 0 | { |
589 | 0 | m_oSRS.Clear(); |
590 | 0 | if (poSRS) |
591 | 0 | m_oSRS = *poSRS; |
592 | |
|
593 | 0 | return CE_None; |
594 | 0 | } |
595 | | |
596 | | /************************************************************************/ |
597 | | /* GetGeoTransform() */ |
598 | | /************************************************************************/ |
599 | | |
600 | | CPLErr MEMDataset::GetGeoTransform(double *padfGeoTransform) |
601 | | |
602 | 0 | { |
603 | 0 | memcpy(padfGeoTransform, adfGeoTransform, sizeof(double) * 6); |
604 | 0 | if (bGeoTransformSet) |
605 | 0 | return CE_None; |
606 | | |
607 | 0 | return CE_Failure; |
608 | 0 | } |
609 | | |
610 | | /************************************************************************/ |
611 | | /* SetGeoTransform() */ |
612 | | /************************************************************************/ |
613 | | |
614 | | CPLErr MEMDataset::SetGeoTransform(double *padfGeoTransform) |
615 | | |
616 | 0 | { |
617 | 0 | memcpy(adfGeoTransform, padfGeoTransform, sizeof(double) * 6); |
618 | 0 | bGeoTransformSet = TRUE; |
619 | |
|
620 | 0 | return CE_None; |
621 | 0 | } |
622 | | |
623 | | /************************************************************************/ |
624 | | /* GetInternalHandle() */ |
625 | | /************************************************************************/ |
626 | | |
627 | | void *MEMDataset::GetInternalHandle(const char *pszRequest) |
628 | | |
629 | 0 | { |
630 | | // check for MEMORYnnn string in pszRequest (nnnn can be up to 10 |
631 | | // digits, or even omitted) |
632 | 0 | if (STARTS_WITH_CI(pszRequest, "MEMORY")) |
633 | 0 | { |
634 | 0 | if (int BandNumber = static_cast<int>(CPLScanLong(&pszRequest[6], 10))) |
635 | 0 | { |
636 | 0 | MEMRasterBand *RequestedRasterBand = |
637 | 0 | cpl::down_cast<MEMRasterBand *>(GetRasterBand(BandNumber)); |
638 | | |
639 | | // we're within a MEMDataset so the only thing a RasterBand |
640 | | // could be is a MEMRasterBand |
641 | |
|
642 | 0 | if (RequestedRasterBand != nullptr) |
643 | 0 | { |
644 | | // return the internal band data pointer |
645 | 0 | return RequestedRasterBand->GetData(); |
646 | 0 | } |
647 | 0 | } |
648 | 0 | } |
649 | | |
650 | 0 | return nullptr; |
651 | 0 | } |
652 | | |
653 | | /************************************************************************/ |
654 | | /* GetGCPCount() */ |
655 | | /************************************************************************/ |
656 | | |
657 | | int MEMDataset::GetGCPCount() |
658 | | |
659 | 0 | { |
660 | 0 | return static_cast<int>(m_aoGCPs.size()); |
661 | 0 | } |
662 | | |
663 | | /************************************************************************/ |
664 | | /* GetGCPSpatialRef() */ |
665 | | /************************************************************************/ |
666 | | |
667 | | const OGRSpatialReference *MEMDataset::GetGCPSpatialRef() const |
668 | | |
669 | 0 | { |
670 | 0 | return m_oGCPSRS.IsEmpty() ? nullptr : &m_oGCPSRS; |
671 | 0 | } |
672 | | |
673 | | /************************************************************************/ |
674 | | /* GetGCPs() */ |
675 | | /************************************************************************/ |
676 | | |
677 | | const GDAL_GCP *MEMDataset::GetGCPs() |
678 | | |
679 | 0 | { |
680 | 0 | return gdal::GCP::c_ptr(m_aoGCPs); |
681 | 0 | } |
682 | | |
683 | | /************************************************************************/ |
684 | | /* SetGCPs() */ |
685 | | /************************************************************************/ |
686 | | |
687 | | CPLErr MEMDataset::SetGCPs(int nNewCount, const GDAL_GCP *pasNewGCPList, |
688 | | const OGRSpatialReference *poSRS) |
689 | | |
690 | 0 | { |
691 | 0 | m_oGCPSRS.Clear(); |
692 | 0 | if (poSRS) |
693 | 0 | m_oGCPSRS = *poSRS; |
694 | |
|
695 | 0 | m_aoGCPs = gdal::GCP::fromC(pasNewGCPList, nNewCount); |
696 | |
|
697 | 0 | return CE_None; |
698 | 0 | } |
699 | | |
700 | | /************************************************************************/ |
701 | | /* AddBand() */ |
702 | | /* */ |
703 | | /* Add a new band to the dataset, allowing creation options to */ |
704 | | /* specify the existing memory to use, otherwise create new */ |
705 | | /* memory. */ |
706 | | /************************************************************************/ |
707 | | |
708 | | CPLErr MEMDataset::AddBand(GDALDataType eType, char **papszOptions) |
709 | | |
710 | 0 | { |
711 | 0 | const int nBandId = GetRasterCount() + 1; |
712 | 0 | const GSpacing nPixelSize = GDALGetDataTypeSizeBytes(eType); |
713 | 0 | if (nPixelSize == 0) |
714 | 0 | { |
715 | 0 | ReportError(CE_Failure, CPLE_IllegalArg, |
716 | 0 | "Illegal GDT_Unknown/GDT_TypeCount argument"); |
717 | 0 | return CE_Failure; |
718 | 0 | } |
719 | | |
720 | | /* -------------------------------------------------------------------- */ |
721 | | /* Do we need to allocate the memory ourselves? This is the */ |
722 | | /* simple case. */ |
723 | | /* -------------------------------------------------------------------- */ |
724 | 0 | if (CSLFetchNameValue(papszOptions, "DATAPOINTER") == nullptr) |
725 | 0 | { |
726 | 0 | const GSpacing nTmp = nPixelSize * GetRasterXSize(); |
727 | 0 | GByte *pData = |
728 | | #if SIZEOF_VOIDP == 4 |
729 | | (nTmp > INT_MAX) ? nullptr : |
730 | | #endif |
731 | 0 | static_cast<GByte *>(VSI_CALLOC_VERBOSE( |
732 | 0 | static_cast<size_t>(nTmp), GetRasterYSize())); |
733 | |
|
734 | 0 | if (pData == nullptr) |
735 | 0 | { |
736 | 0 | return CE_Failure; |
737 | 0 | } |
738 | | |
739 | 0 | SetBand(nBandId, |
740 | 0 | new MEMRasterBand(this, nBandId, pData, eType, nPixelSize, |
741 | 0 | nPixelSize * GetRasterXSize(), TRUE)); |
742 | |
|
743 | 0 | return CE_None; |
744 | 0 | } |
745 | | |
746 | | /* -------------------------------------------------------------------- */ |
747 | | /* Get layout of memory and other flags. */ |
748 | | /* -------------------------------------------------------------------- */ |
749 | 0 | const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER"); |
750 | 0 | GByte *pData = static_cast<GByte *>(CPLScanPointer( |
751 | 0 | pszDataPointer, static_cast<int>(strlen(pszDataPointer)))); |
752 | |
|
753 | 0 | const char *pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET"); |
754 | 0 | GSpacing nPixelOffset; |
755 | 0 | if (pszOption == nullptr) |
756 | 0 | nPixelOffset = nPixelSize; |
757 | 0 | else |
758 | 0 | nPixelOffset = CPLAtoGIntBig(pszOption); |
759 | |
|
760 | 0 | pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET"); |
761 | 0 | GSpacing nLineOffset; |
762 | 0 | if (pszOption == nullptr) |
763 | 0 | nLineOffset = GetRasterXSize() * static_cast<size_t>(nPixelOffset); |
764 | 0 | else |
765 | 0 | nLineOffset = CPLAtoGIntBig(pszOption); |
766 | |
|
767 | 0 | SetBand(nBandId, new MEMRasterBand(this, nBandId, pData, eType, |
768 | 0 | nPixelOffset, nLineOffset, FALSE)); |
769 | |
|
770 | 0 | return CE_None; |
771 | 0 | } |
772 | | |
773 | | /************************************************************************/ |
774 | | /* AddMEMBand() */ |
775 | | /************************************************************************/ |
776 | | |
777 | | void MEMDataset::AddMEMBand(GDALRasterBandH hMEMBand) |
778 | 0 | { |
779 | 0 | auto poBand = GDALRasterBand::FromHandle(hMEMBand); |
780 | 0 | CPLAssert(dynamic_cast<MEMRasterBand *>(poBand) != nullptr); |
781 | 0 | SetBand(1 + nBands, poBand); |
782 | 0 | } |
783 | | |
784 | | /************************************************************************/ |
785 | | /* IBuildOverviews() */ |
786 | | /************************************************************************/ |
787 | | |
788 | | CPLErr MEMDataset::IBuildOverviews(const char *pszResampling, int nOverviews, |
789 | | const int *panOverviewList, int nListBands, |
790 | | const int *panBandList, |
791 | | GDALProgressFunc pfnProgress, |
792 | | void *pProgressData, |
793 | | CSLConstList papszOptions) |
794 | 0 | { |
795 | 0 | if (nBands == 0) |
796 | 0 | { |
797 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Dataset has zero bands."); |
798 | 0 | return CE_Failure; |
799 | 0 | } |
800 | | |
801 | 0 | if (nListBands != nBands) |
802 | 0 | { |
803 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
804 | 0 | "Generation of overviews in MEM only" |
805 | 0 | "supported when operating on all bands."); |
806 | 0 | return CE_Failure; |
807 | 0 | } |
808 | | |
809 | 0 | if (nOverviews == 0) |
810 | 0 | { |
811 | | // Cleanup existing overviews |
812 | 0 | m_apoOverviewDS.clear(); |
813 | 0 | return CE_None; |
814 | 0 | } |
815 | | |
816 | | /* -------------------------------------------------------------------- */ |
817 | | /* Force cascading. Help to get accurate results when masks are */ |
818 | | /* involved. */ |
819 | | /* -------------------------------------------------------------------- */ |
820 | 0 | if (nOverviews > 1 && |
821 | 0 | (STARTS_WITH_CI(pszResampling, "AVER") || |
822 | 0 | STARTS_WITH_CI(pszResampling, "GAUSS") || |
823 | 0 | EQUAL(pszResampling, "CUBIC") || EQUAL(pszResampling, "CUBICSPLINE") || |
824 | 0 | EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR"))) |
825 | 0 | { |
826 | 0 | double dfTotalPixels = 0; |
827 | 0 | for (int i = 0; i < nOverviews; i++) |
828 | 0 | { |
829 | 0 | dfTotalPixels += static_cast<double>(nRasterXSize) * nRasterYSize / |
830 | 0 | (panOverviewList[i] * panOverviewList[i]); |
831 | 0 | } |
832 | |
|
833 | 0 | double dfAccPixels = 0; |
834 | 0 | for (int i = 0; i < nOverviews; i++) |
835 | 0 | { |
836 | 0 | double dfPixels = static_cast<double>(nRasterXSize) * nRasterYSize / |
837 | 0 | (panOverviewList[i] * panOverviewList[i]); |
838 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
839 | 0 | dfAccPixels / dfTotalPixels, |
840 | 0 | (dfAccPixels + dfPixels) / dfTotalPixels, pfnProgress, |
841 | 0 | pProgressData); |
842 | 0 | CPLErr eErr = IBuildOverviews( |
843 | 0 | pszResampling, 1, &panOverviewList[i], nListBands, panBandList, |
844 | 0 | GDALScaledProgress, pScaledProgress, papszOptions); |
845 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
846 | 0 | dfAccPixels += dfPixels; |
847 | 0 | if (eErr == CE_Failure) |
848 | 0 | return eErr; |
849 | 0 | } |
850 | 0 | return CE_None; |
851 | 0 | } |
852 | | |
853 | | /* -------------------------------------------------------------------- */ |
854 | | /* Establish which of the overview levels we already have, and */ |
855 | | /* which are new. */ |
856 | | /* -------------------------------------------------------------------- */ |
857 | 0 | GDALRasterBand *poBand = GetRasterBand(1); |
858 | |
|
859 | 0 | for (int i = 0; i < nOverviews; i++) |
860 | 0 | { |
861 | 0 | bool bExisting = false; |
862 | 0 | for (int j = 0; j < poBand->GetOverviewCount(); j++) |
863 | 0 | { |
864 | 0 | GDALRasterBand *poOverview = poBand->GetOverview(j); |
865 | 0 | if (poOverview == nullptr) |
866 | 0 | continue; |
867 | | |
868 | 0 | int nOvFactor = |
869 | 0 | GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(), |
870 | 0 | poOverview->GetYSize(), poBand->GetYSize()); |
871 | |
|
872 | 0 | if (nOvFactor == panOverviewList[i] || |
873 | 0 | nOvFactor == GDALOvLevelAdjust2(panOverviewList[i], |
874 | 0 | poBand->GetXSize(), |
875 | 0 | poBand->GetYSize())) |
876 | 0 | { |
877 | 0 | bExisting = true; |
878 | 0 | break; |
879 | 0 | } |
880 | 0 | } |
881 | | |
882 | | // Create new overview dataset if needed. |
883 | 0 | if (!bExisting) |
884 | 0 | { |
885 | 0 | auto poOvrDS = std::make_unique<MEMDataset>(); |
886 | 0 | poOvrDS->eAccess = GA_Update; |
887 | 0 | poOvrDS->nRasterXSize = |
888 | 0 | DIV_ROUND_UP(nRasterXSize, panOverviewList[i]); |
889 | 0 | poOvrDS->nRasterYSize = |
890 | 0 | DIV_ROUND_UP(nRasterYSize, panOverviewList[i]); |
891 | 0 | poOvrDS->bGeoTransformSet = bGeoTransformSet; |
892 | 0 | memcpy(poOvrDS->adfGeoTransform, adfGeoTransform, |
893 | 0 | 6 * sizeof(double)); |
894 | 0 | const double dfOvrXRatio = |
895 | 0 | static_cast<double>(nRasterXSize) / poOvrDS->nRasterXSize; |
896 | 0 | const double dfOvrYRatio = |
897 | 0 | static_cast<double>(nRasterYSize) / poOvrDS->nRasterYSize; |
898 | 0 | GDALRescaleGeoTransform(poOvrDS->adfGeoTransform, dfOvrXRatio, |
899 | 0 | dfOvrYRatio); |
900 | 0 | poOvrDS->m_oSRS = m_oSRS; |
901 | 0 | for (int iBand = 0; iBand < nBands; iBand++) |
902 | 0 | { |
903 | 0 | const GDALDataType eDT = |
904 | 0 | GetRasterBand(iBand + 1)->GetRasterDataType(); |
905 | 0 | if (poOvrDS->AddBand(eDT, nullptr) != CE_None) |
906 | 0 | { |
907 | 0 | return CE_Failure; |
908 | 0 | } |
909 | 0 | } |
910 | 0 | m_apoOverviewDS.emplace_back(poOvrDS.release()); |
911 | 0 | } |
912 | 0 | } |
913 | | |
914 | | /* -------------------------------------------------------------------- */ |
915 | | /* Build band list. */ |
916 | | /* -------------------------------------------------------------------- */ |
917 | 0 | GDALRasterBand **pahBands = static_cast<GDALRasterBand **>( |
918 | 0 | CPLCalloc(sizeof(GDALRasterBand *), nBands)); |
919 | 0 | for (int i = 0; i < nBands; i++) |
920 | 0 | pahBands[i] = GetRasterBand(panBandList[i]); |
921 | | |
922 | | /* -------------------------------------------------------------------- */ |
923 | | /* Refresh overviews that were listed. */ |
924 | | /* -------------------------------------------------------------------- */ |
925 | 0 | GDALRasterBand **papoOverviewBands = |
926 | 0 | static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews)); |
927 | 0 | GDALRasterBand **papoMaskOverviewBands = |
928 | 0 | static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews)); |
929 | |
|
930 | 0 | CPLErr eErr = CE_None; |
931 | 0 | for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++) |
932 | 0 | { |
933 | 0 | poBand = GetRasterBand(panBandList[iBand]); |
934 | |
|
935 | 0 | int nNewOverviews = 0; |
936 | 0 | for (int i = 0; i < nOverviews; i++) |
937 | 0 | { |
938 | 0 | for (int j = 0; j < poBand->GetOverviewCount(); j++) |
939 | 0 | { |
940 | 0 | GDALRasterBand *poOverview = poBand->GetOverview(j); |
941 | |
|
942 | 0 | int bHasNoData = FALSE; |
943 | 0 | double noDataValue = poBand->GetNoDataValue(&bHasNoData); |
944 | |
|
945 | 0 | if (bHasNoData) |
946 | 0 | poOverview->SetNoDataValue(noDataValue); |
947 | |
|
948 | 0 | const int nOvFactor = GDALComputeOvFactor( |
949 | 0 | poOverview->GetXSize(), poBand->GetXSize(), |
950 | 0 | poOverview->GetYSize(), poBand->GetYSize()); |
951 | |
|
952 | 0 | if (nOvFactor == panOverviewList[i] || |
953 | 0 | nOvFactor == GDALOvLevelAdjust2(panOverviewList[i], |
954 | 0 | poBand->GetXSize(), |
955 | 0 | poBand->GetYSize())) |
956 | 0 | { |
957 | 0 | papoOverviewBands[nNewOverviews++] = poOverview; |
958 | 0 | break; |
959 | 0 | } |
960 | 0 | } |
961 | 0 | } |
962 | | |
963 | | // If the band has an explicit mask, we need to create overviews |
964 | | // for it |
965 | 0 | MEMRasterBand *poMEMBand = cpl::down_cast<MEMRasterBand *>(poBand); |
966 | 0 | const bool bMustGenerateMaskOvr = |
967 | 0 | ((poMEMBand->poMask != nullptr && poMEMBand->poMask.IsOwned()) || |
968 | | // Or if it is a per-dataset mask, in which case just do it for the |
969 | | // first band |
970 | 0 | ((poMEMBand->nMaskFlags & GMF_PER_DATASET) != 0 && iBand == 0)) && |
971 | 0 | dynamic_cast<MEMRasterBand *>(poBand->GetMaskBand()) != nullptr; |
972 | |
|
973 | 0 | if (nNewOverviews > 0 && bMustGenerateMaskOvr) |
974 | 0 | { |
975 | 0 | for (int i = 0; i < nNewOverviews; i++) |
976 | 0 | { |
977 | 0 | MEMRasterBand *poMEMOvrBand = |
978 | 0 | cpl::down_cast<MEMRasterBand *>(papoOverviewBands[i]); |
979 | 0 | if (!(poMEMOvrBand->poMask != nullptr && |
980 | 0 | poMEMOvrBand->poMask.IsOwned()) && |
981 | 0 | (poMEMOvrBand->nMaskFlags & GMF_PER_DATASET) == 0) |
982 | 0 | { |
983 | 0 | poMEMOvrBand->CreateMaskBand(poMEMBand->nMaskFlags); |
984 | 0 | } |
985 | 0 | papoMaskOverviewBands[i] = poMEMOvrBand->GetMaskBand(); |
986 | 0 | } |
987 | |
|
988 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
989 | 0 | 1.0 * iBand / nBands, 1.0 * (iBand + 0.5) / nBands, pfnProgress, |
990 | 0 | pProgressData); |
991 | |
|
992 | 0 | MEMRasterBand *poMaskBand = |
993 | 0 | cpl::down_cast<MEMRasterBand *>(poBand->GetMaskBand()); |
994 | | // Make the mask band to be its own mask, similarly to what is |
995 | | // done for alpha bands in GDALRegenerateOverviews() (#5640) |
996 | 0 | poMaskBand->InvalidateMaskBand(); |
997 | 0 | poMaskBand->poMask.reset(poMaskBand, false); |
998 | 0 | poMaskBand->nMaskFlags = 0; |
999 | 0 | eErr = GDALRegenerateOverviewsEx( |
1000 | 0 | GDALRasterBand::ToHandle(poMaskBand), nNewOverviews, |
1001 | 0 | reinterpret_cast<GDALRasterBandH *>(papoMaskOverviewBands), |
1002 | 0 | pszResampling, GDALScaledProgress, pScaledProgress, |
1003 | 0 | papszOptions); |
1004 | 0 | poMaskBand->InvalidateMaskBand(); |
1005 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
1006 | 0 | } |
1007 | | |
1008 | | // Generate overview of bands *AFTER* mask overviews |
1009 | 0 | if (nNewOverviews > 0 && eErr == CE_None) |
1010 | 0 | { |
1011 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
1012 | 0 | 1.0 * (iBand + (bMustGenerateMaskOvr ? 0.5 : 1)) / nBands, |
1013 | 0 | 1.0 * (iBand + 1) / nBands, pfnProgress, pProgressData); |
1014 | 0 | eErr = GDALRegenerateOverviewsEx( |
1015 | 0 | GDALRasterBand::ToHandle(poBand), nNewOverviews, |
1016 | 0 | reinterpret_cast<GDALRasterBandH *>(papoOverviewBands), |
1017 | 0 | pszResampling, GDALScaledProgress, pScaledProgress, |
1018 | 0 | papszOptions); |
1019 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
1020 | 0 | } |
1021 | 0 | } |
1022 | | |
1023 | | /* -------------------------------------------------------------------- */ |
1024 | | /* Cleanup */ |
1025 | | /* -------------------------------------------------------------------- */ |
1026 | 0 | CPLFree(papoOverviewBands); |
1027 | 0 | CPLFree(papoMaskOverviewBands); |
1028 | 0 | CPLFree(pahBands); |
1029 | |
|
1030 | 0 | return eErr; |
1031 | 0 | } |
1032 | | |
1033 | | /************************************************************************/ |
1034 | | /* CreateMaskBand() */ |
1035 | | /************************************************************************/ |
1036 | | |
1037 | | CPLErr MEMDataset::CreateMaskBand(int nFlagsIn) |
1038 | 0 | { |
1039 | 0 | GDALRasterBand *poFirstBand = GetRasterBand(1); |
1040 | 0 | if (poFirstBand == nullptr) |
1041 | 0 | return CE_Failure; |
1042 | 0 | return poFirstBand->CreateMaskBand(nFlagsIn | GMF_PER_DATASET); |
1043 | 0 | } |
1044 | | |
1045 | | /************************************************************************/ |
1046 | | /* CanBeCloned() */ |
1047 | | /************************************************************************/ |
1048 | | |
1049 | | /** Implements GDALDataset::CanBeCloned() |
1050 | | * |
1051 | | * This method is called by GDALThreadSafeDataset::Create() to determine if |
1052 | | * it is possible to create a thread-safe wrapper for a dataset, which involves |
1053 | | * the ability to Clone() it. |
1054 | | * |
1055 | | * The implementation of this method must be thread-safe. |
1056 | | */ |
1057 | | bool MEMDataset::CanBeCloned(int nScopeFlags, bool bCanShareState) const |
1058 | 0 | { |
1059 | 0 | return nScopeFlags == GDAL_OF_RASTER && bCanShareState && |
1060 | 0 | typeid(this) == typeid(const MEMDataset *); |
1061 | 0 | } |
1062 | | |
1063 | | /************************************************************************/ |
1064 | | /* Clone() */ |
1065 | | /************************************************************************/ |
1066 | | |
1067 | | /** Implements GDALDataset::Clone() |
1068 | | * |
1069 | | * This method returns a new instance, identical to "this", but which shares the |
1070 | | * same memory buffer as "this". |
1071 | | * |
1072 | | * The implementation of this method must be thread-safe. |
1073 | | */ |
1074 | | std::unique_ptr<GDALDataset> MEMDataset::Clone(int nScopeFlags, |
1075 | | bool bCanShareState) const |
1076 | 0 | { |
1077 | 0 | if (MEMDataset::CanBeCloned(nScopeFlags, bCanShareState)) |
1078 | 0 | { |
1079 | 0 | auto poNewDS = std::make_unique<MEMDataset>(); |
1080 | 0 | poNewDS->poDriver = poDriver; |
1081 | 0 | poNewDS->nRasterXSize = nRasterXSize; |
1082 | 0 | poNewDS->nRasterYSize = nRasterYSize; |
1083 | 0 | poNewDS->bGeoTransformSet = bGeoTransformSet; |
1084 | 0 | memcpy(poNewDS->adfGeoTransform, adfGeoTransform, |
1085 | 0 | sizeof(adfGeoTransform)); |
1086 | 0 | poNewDS->m_oSRS = m_oSRS; |
1087 | 0 | poNewDS->m_aoGCPs = m_aoGCPs; |
1088 | 0 | poNewDS->m_oGCPSRS = m_oGCPSRS; |
1089 | 0 | for (const auto &poOvrDS : m_apoOverviewDS) |
1090 | 0 | { |
1091 | 0 | poNewDS->m_apoOverviewDS.emplace_back( |
1092 | 0 | poOvrDS->Clone(nScopeFlags, bCanShareState).release()); |
1093 | 0 | } |
1094 | |
|
1095 | 0 | poNewDS->SetDescription(GetDescription()); |
1096 | 0 | poNewDS->oMDMD = oMDMD; |
1097 | | |
1098 | | // Clone bands |
1099 | 0 | for (int i = 1; i <= nBands; ++i) |
1100 | 0 | { |
1101 | 0 | auto poSrcMEMBand = |
1102 | 0 | dynamic_cast<const MEMRasterBand *>(papoBands[i - 1]); |
1103 | 0 | CPLAssert(poSrcMEMBand); |
1104 | 0 | auto poNewBand = std::make_unique<MEMRasterBand>( |
1105 | 0 | poNewDS.get(), i, poSrcMEMBand->pabyData, |
1106 | 0 | poSrcMEMBand->GetRasterDataType(), poSrcMEMBand->nPixelOffset, |
1107 | 0 | poSrcMEMBand->nLineOffset, |
1108 | 0 | /* bAssumeOwnership = */ false); |
1109 | |
|
1110 | 0 | poNewBand->SetDescription(poSrcMEMBand->GetDescription()); |
1111 | 0 | poNewBand->oMDMD = poSrcMEMBand->oMDMD; |
1112 | |
|
1113 | 0 | if (poSrcMEMBand->psPam) |
1114 | 0 | { |
1115 | 0 | poNewBand->PamInitialize(); |
1116 | 0 | CPLAssert(poNewBand->psPam); |
1117 | 0 | poNewBand->psPam->CopyFrom(*(poSrcMEMBand->psPam)); |
1118 | 0 | } |
1119 | | |
1120 | | // Instantiates a mask band when needed. |
1121 | 0 | if ((poSrcMEMBand->nMaskFlags & |
1122 | 0 | (GMF_ALL_VALID | GMF_ALPHA | GMF_NODATA)) == 0) |
1123 | 0 | { |
1124 | 0 | auto poSrcMaskBand = dynamic_cast<const MEMRasterBand *>( |
1125 | 0 | poSrcMEMBand->poMask.get()); |
1126 | 0 | if (poSrcMaskBand) |
1127 | 0 | { |
1128 | 0 | auto poMaskBand = new MEMRasterBand( |
1129 | 0 | poSrcMaskBand->pabyData, GDT_Byte, nRasterXSize, |
1130 | 0 | nRasterYSize, /* bOwnData = */ false); |
1131 | 0 | poMaskBand->m_bIsMask = true; |
1132 | 0 | poNewBand->poMask.reset(poMaskBand, true); |
1133 | 0 | poNewBand->nMaskFlags = poSrcMaskBand->nMaskFlags; |
1134 | 0 | } |
1135 | 0 | } |
1136 | |
|
1137 | 0 | poNewDS->SetBand(i, std::move(poNewBand)); |
1138 | 0 | } |
1139 | | |
1140 | 0 | return poNewDS; |
1141 | 0 | } |
1142 | 0 | return GDALDataset::Clone(nScopeFlags, bCanShareState); |
1143 | 0 | } |
1144 | | |
1145 | | /************************************************************************/ |
1146 | | /* Open() */ |
1147 | | /************************************************************************/ |
1148 | | |
1149 | | GDALDataset *MEMDataset::Open(GDALOpenInfo *poOpenInfo) |
1150 | | |
1151 | 0 | { |
1152 | | /* -------------------------------------------------------------------- */ |
1153 | | /* Do we have the special filename signature for MEM format */ |
1154 | | /* description strings? */ |
1155 | | /* -------------------------------------------------------------------- */ |
1156 | 0 | if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "MEM:::") || |
1157 | 0 | poOpenInfo->fpL != nullptr) |
1158 | 0 | return nullptr; |
1159 | | |
1160 | 0 | #ifndef GDAL_MEM_ENABLE_OPEN |
1161 | 0 | if (!CPLTestBool(CPLGetConfigOption("GDAL_MEM_ENABLE_OPEN", "NO"))) |
1162 | 0 | { |
1163 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1164 | 0 | "Opening a MEM dataset with the MEM:::DATAPOINTER= syntax " |
1165 | 0 | "is no longer supported by default for security reasons. " |
1166 | 0 | "If you want to allow it, define the " |
1167 | 0 | "GDAL_MEM_ENABLE_OPEN " |
1168 | 0 | "configuration option to YES, or build GDAL with the " |
1169 | 0 | "GDAL_MEM_ENABLE_OPEN compilation definition"); |
1170 | 0 | return nullptr; |
1171 | 0 | } |
1172 | 0 | #endif |
1173 | | |
1174 | 0 | char **papszOptions = |
1175 | 0 | CSLTokenizeStringComplex(poOpenInfo->pszFilename + 6, ",", TRUE, FALSE); |
1176 | | |
1177 | | /* -------------------------------------------------------------------- */ |
1178 | | /* Verify we have all required fields */ |
1179 | | /* -------------------------------------------------------------------- */ |
1180 | 0 | if (CSLFetchNameValue(papszOptions, "PIXELS") == nullptr || |
1181 | 0 | CSLFetchNameValue(papszOptions, "LINES") == nullptr || |
1182 | 0 | CSLFetchNameValue(papszOptions, "DATAPOINTER") == nullptr) |
1183 | 0 | { |
1184 | 0 | CPLError( |
1185 | 0 | CE_Failure, CPLE_AppDefined, |
1186 | 0 | "Missing required field (one of PIXELS, LINES or DATAPOINTER). " |
1187 | 0 | "Unable to access in-memory array."); |
1188 | |
|
1189 | 0 | CSLDestroy(papszOptions); |
1190 | 0 | return nullptr; |
1191 | 0 | } |
1192 | | |
1193 | | /* -------------------------------------------------------------------- */ |
1194 | | /* Create the new MEMDataset object. */ |
1195 | | /* -------------------------------------------------------------------- */ |
1196 | 0 | MEMDataset *poDS = new MEMDataset(); |
1197 | |
|
1198 | 0 | poDS->nRasterXSize = atoi(CSLFetchNameValue(papszOptions, "PIXELS")); |
1199 | 0 | poDS->nRasterYSize = atoi(CSLFetchNameValue(papszOptions, "LINES")); |
1200 | 0 | poDS->eAccess = poOpenInfo->eAccess; |
1201 | | |
1202 | | /* -------------------------------------------------------------------- */ |
1203 | | /* Extract other information. */ |
1204 | | /* -------------------------------------------------------------------- */ |
1205 | 0 | const char *pszOption = CSLFetchNameValue(papszOptions, "BANDS"); |
1206 | 0 | int nBands = 1; |
1207 | 0 | if (pszOption != nullptr) |
1208 | 0 | { |
1209 | 0 | nBands = atoi(pszOption); |
1210 | 0 | } |
1211 | |
|
1212 | 0 | if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || |
1213 | 0 | !GDALCheckBandCount(nBands, TRUE)) |
1214 | 0 | { |
1215 | 0 | CSLDestroy(papszOptions); |
1216 | 0 | delete poDS; |
1217 | 0 | return nullptr; |
1218 | 0 | } |
1219 | | |
1220 | 0 | pszOption = CSLFetchNameValue(papszOptions, "DATATYPE"); |
1221 | 0 | GDALDataType eType = GDT_Byte; |
1222 | 0 | if (pszOption != nullptr) |
1223 | 0 | { |
1224 | 0 | if (atoi(pszOption) > 0 && atoi(pszOption) < GDT_TypeCount) |
1225 | 0 | eType = static_cast<GDALDataType>(atoi(pszOption)); |
1226 | 0 | else |
1227 | 0 | { |
1228 | 0 | eType = GDALGetDataTypeByName(pszOption); |
1229 | 0 | if (eType == GDT_Unknown) |
1230 | 0 | { |
1231 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1232 | 0 | "DATATYPE=%s not recognised.", pszOption); |
1233 | 0 | CSLDestroy(papszOptions); |
1234 | 0 | delete poDS; |
1235 | 0 | return nullptr; |
1236 | 0 | } |
1237 | 0 | } |
1238 | 0 | } |
1239 | | |
1240 | 0 | pszOption = CSLFetchNameValue(papszOptions, "PIXELOFFSET"); |
1241 | 0 | GSpacing nPixelOffset; |
1242 | 0 | if (pszOption == nullptr) |
1243 | 0 | nPixelOffset = GDALGetDataTypeSizeBytes(eType); |
1244 | 0 | else |
1245 | 0 | nPixelOffset = |
1246 | 0 | CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption))); |
1247 | |
|
1248 | 0 | pszOption = CSLFetchNameValue(papszOptions, "LINEOFFSET"); |
1249 | 0 | GSpacing nLineOffset = 0; |
1250 | 0 | if (pszOption == nullptr) |
1251 | 0 | nLineOffset = poDS->nRasterXSize * static_cast<size_t>(nPixelOffset); |
1252 | 0 | else |
1253 | 0 | nLineOffset = |
1254 | 0 | CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption))); |
1255 | |
|
1256 | 0 | pszOption = CSLFetchNameValue(papszOptions, "BANDOFFSET"); |
1257 | 0 | GSpacing nBandOffset = 0; |
1258 | 0 | if (pszOption == nullptr) |
1259 | 0 | nBandOffset = nLineOffset * static_cast<size_t>(poDS->nRasterYSize); |
1260 | 0 | else |
1261 | 0 | nBandOffset = |
1262 | 0 | CPLScanUIntBig(pszOption, static_cast<int>(strlen(pszOption))); |
1263 | |
|
1264 | 0 | const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER"); |
1265 | 0 | GByte *pabyData = static_cast<GByte *>(CPLScanPointer( |
1266 | 0 | pszDataPointer, static_cast<int>(strlen(pszDataPointer)))); |
1267 | | |
1268 | | /* -------------------------------------------------------------------- */ |
1269 | | /* Create band information objects. */ |
1270 | | /* -------------------------------------------------------------------- */ |
1271 | 0 | for (int iBand = 0; iBand < nBands; iBand++) |
1272 | 0 | { |
1273 | 0 | poDS->SetBand(iBand + 1, |
1274 | 0 | new MEMRasterBand(poDS, iBand + 1, |
1275 | 0 | pabyData + iBand * nBandOffset, eType, |
1276 | 0 | nPixelOffset, nLineOffset, FALSE)); |
1277 | 0 | } |
1278 | | |
1279 | | /* -------------------------------------------------------------------- */ |
1280 | | /* Set GeoTransform information. */ |
1281 | | /* -------------------------------------------------------------------- */ |
1282 | |
|
1283 | 0 | pszOption = CSLFetchNameValue(papszOptions, "GEOTRANSFORM"); |
1284 | 0 | if (pszOption != nullptr) |
1285 | 0 | { |
1286 | 0 | char **values = CSLTokenizeStringComplex(pszOption, "/", TRUE, FALSE); |
1287 | 0 | if (CSLCount(values) == 6) |
1288 | 0 | { |
1289 | 0 | double adfGeoTransform[6] = {0, 0, 0, 0, 0, 0}; |
1290 | 0 | for (size_t i = 0; i < 6; ++i) |
1291 | 0 | { |
1292 | 0 | adfGeoTransform[i] = CPLScanDouble( |
1293 | 0 | values[i], static_cast<int>(strlen(values[i]))); |
1294 | 0 | } |
1295 | 0 | poDS->SetGeoTransform(adfGeoTransform); |
1296 | 0 | } |
1297 | 0 | CSLDestroy(values); |
1298 | 0 | } |
1299 | | |
1300 | | /* -------------------------------------------------------------------- */ |
1301 | | /* Set Projection Information */ |
1302 | | /* -------------------------------------------------------------------- */ |
1303 | |
|
1304 | 0 | pszOption = CSLFetchNameValue(papszOptions, "SPATIALREFERENCE"); |
1305 | 0 | if (pszOption != nullptr) |
1306 | 0 | { |
1307 | 0 | poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
1308 | 0 | if (poDS->m_oSRS.SetFromUserInput(pszOption) != OGRERR_NONE) |
1309 | 0 | { |
1310 | 0 | CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized crs: %s", |
1311 | 0 | pszOption); |
1312 | 0 | } |
1313 | 0 | } |
1314 | | /* -------------------------------------------------------------------- */ |
1315 | | /* Try to return a regular handle on the file. */ |
1316 | | /* -------------------------------------------------------------------- */ |
1317 | 0 | CSLDestroy(papszOptions); |
1318 | 0 | return poDS; |
1319 | 0 | } |
1320 | | |
1321 | | /************************************************************************/ |
1322 | | /* Create() */ |
1323 | | /************************************************************************/ |
1324 | | |
1325 | | MEMDataset *MEMDataset::Create(const char * /* pszFilename */, int nXSize, |
1326 | | int nYSize, int nBandsIn, GDALDataType eType, |
1327 | | char **papszOptions) |
1328 | 0 | { |
1329 | | |
1330 | | /* -------------------------------------------------------------------- */ |
1331 | | /* Do we want a pixel interleaved buffer? I mostly care about */ |
1332 | | /* this to test pixel interleaved IO in other contexts, but it */ |
1333 | | /* could be useful to create a directly accessible buffer for */ |
1334 | | /* some apps. */ |
1335 | | /* -------------------------------------------------------------------- */ |
1336 | 0 | bool bPixelInterleaved = false; |
1337 | 0 | const char *pszOption = CSLFetchNameValue(papszOptions, "INTERLEAVE"); |
1338 | 0 | if (pszOption && EQUAL(pszOption, "PIXEL")) |
1339 | 0 | bPixelInterleaved = true; |
1340 | | |
1341 | | /* -------------------------------------------------------------------- */ |
1342 | | /* First allocate band data, verifying that we can get enough */ |
1343 | | /* memory. */ |
1344 | | /* -------------------------------------------------------------------- */ |
1345 | 0 | const int nWordSize = GDALGetDataTypeSizeBytes(eType); |
1346 | 0 | if (nBandsIn > 0 && nWordSize > 0 && |
1347 | 0 | (nBandsIn > INT_MAX / nWordSize || |
1348 | 0 | static_cast<GIntBig>(nXSize) * nYSize > |
1349 | 0 | GINTBIG_MAX / (nWordSize * nBandsIn))) |
1350 | 0 | { |
1351 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Multiplication overflow"); |
1352 | 0 | return nullptr; |
1353 | 0 | } |
1354 | | |
1355 | 0 | const GUIntBig nGlobalBigSize = |
1356 | 0 | static_cast<GUIntBig>(nWordSize) * nBandsIn * nXSize * nYSize; |
1357 | 0 | const size_t nGlobalSize = static_cast<size_t>(nGlobalBigSize); |
1358 | | #if SIZEOF_VOIDP == 4 |
1359 | | if (static_cast<GUIntBig>(nGlobalSize) != nGlobalBigSize) |
1360 | | { |
1361 | | CPLError(CE_Failure, CPLE_OutOfMemory, |
1362 | | "Cannot allocate " CPL_FRMT_GUIB " bytes on this platform.", |
1363 | | nGlobalBigSize); |
1364 | | return nullptr; |
1365 | | } |
1366 | | #endif |
1367 | |
|
1368 | 0 | std::vector<GByte *> apbyBandData; |
1369 | 0 | if (nBandsIn > 0) |
1370 | 0 | { |
1371 | 0 | GByte *pabyData = |
1372 | 0 | static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nGlobalSize)); |
1373 | 0 | if (!pabyData) |
1374 | 0 | { |
1375 | 0 | return nullptr; |
1376 | 0 | } |
1377 | | |
1378 | 0 | if (bPixelInterleaved) |
1379 | 0 | { |
1380 | 0 | for (int iBand = 0; iBand < nBandsIn; iBand++) |
1381 | 0 | { |
1382 | 0 | apbyBandData.push_back(pabyData + iBand * nWordSize); |
1383 | 0 | } |
1384 | 0 | } |
1385 | 0 | else |
1386 | 0 | { |
1387 | 0 | for (int iBand = 0; iBand < nBandsIn; iBand++) |
1388 | 0 | { |
1389 | 0 | apbyBandData.push_back( |
1390 | 0 | pabyData + |
1391 | 0 | (static_cast<size_t>(nWordSize) * nXSize * nYSize) * iBand); |
1392 | 0 | } |
1393 | 0 | } |
1394 | 0 | } |
1395 | | |
1396 | | /* -------------------------------------------------------------------- */ |
1397 | | /* Create the new GTiffDataset object. */ |
1398 | | /* -------------------------------------------------------------------- */ |
1399 | 0 | MEMDataset *poDS = new MEMDataset(); |
1400 | |
|
1401 | 0 | poDS->nRasterXSize = nXSize; |
1402 | 0 | poDS->nRasterYSize = nYSize; |
1403 | 0 | poDS->eAccess = GA_Update; |
1404 | |
|
1405 | 0 | const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE"); |
1406 | 0 | if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE")) |
1407 | 0 | poDS->SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE"); |
1408 | |
|
1409 | 0 | if (bPixelInterleaved) |
1410 | 0 | poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE"); |
1411 | 0 | else |
1412 | 0 | poDS->SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE"); |
1413 | | |
1414 | | /* -------------------------------------------------------------------- */ |
1415 | | /* Create band information objects. */ |
1416 | | /* -------------------------------------------------------------------- */ |
1417 | 0 | for (int iBand = 0; iBand < nBandsIn; iBand++) |
1418 | 0 | { |
1419 | 0 | MEMRasterBand *poNewBand = nullptr; |
1420 | |
|
1421 | 0 | if (bPixelInterleaved) |
1422 | 0 | poNewBand = new MEMRasterBand( |
1423 | 0 | poDS, iBand + 1, apbyBandData[iBand], eType, |
1424 | 0 | cpl::fits_on<int>(nWordSize * nBandsIn), 0, iBand == 0); |
1425 | 0 | else |
1426 | 0 | poNewBand = new MEMRasterBand(poDS, iBand + 1, apbyBandData[iBand], |
1427 | 0 | eType, 0, 0, iBand == 0); |
1428 | |
|
1429 | 0 | poDS->SetBand(iBand + 1, poNewBand); |
1430 | 0 | } |
1431 | | |
1432 | | /* -------------------------------------------------------------------- */ |
1433 | | /* Try to return a regular handle on the file. */ |
1434 | | /* -------------------------------------------------------------------- */ |
1435 | 0 | return poDS; |
1436 | 0 | } |
1437 | | |
1438 | | GDALDataset *MEMDataset::CreateBase(const char *pszFilename, int nXSize, |
1439 | | int nYSize, int nBandsIn, |
1440 | | GDALDataType eType, char **papszOptions) |
1441 | 0 | { |
1442 | 0 | return Create(pszFilename, nXSize, nYSize, nBandsIn, eType, papszOptions); |
1443 | 0 | } |
1444 | | |
1445 | | /************************************************************************/ |
1446 | | /* ~MEMAttributeHolder() */ |
1447 | | /************************************************************************/ |
1448 | | |
1449 | 0 | MEMAttributeHolder::~MEMAttributeHolder() = default; |
1450 | | |
1451 | | /************************************************************************/ |
1452 | | /* RenameAttribute() */ |
1453 | | /************************************************************************/ |
1454 | | |
1455 | | bool MEMAttributeHolder::RenameAttribute(const std::string &osOldName, |
1456 | | const std::string &osNewName) |
1457 | 0 | { |
1458 | 0 | if (m_oMapAttributes.find(osNewName) != m_oMapAttributes.end()) |
1459 | 0 | { |
1460 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1461 | 0 | "An attribute with same name already exists"); |
1462 | 0 | return false; |
1463 | 0 | } |
1464 | 0 | auto oIter = m_oMapAttributes.find(osOldName); |
1465 | 0 | if (oIter == m_oMapAttributes.end()) |
1466 | 0 | { |
1467 | 0 | CPLAssert(false); |
1468 | 0 | return false; |
1469 | 0 | } |
1470 | 0 | auto poAttr = std::move(oIter->second); |
1471 | 0 | m_oMapAttributes.erase(oIter); |
1472 | 0 | m_oMapAttributes[osNewName] = std::move(poAttr); |
1473 | 0 | return true; |
1474 | 0 | } |
1475 | | |
1476 | | /************************************************************************/ |
1477 | | /* GetMDArrayNames() */ |
1478 | | /************************************************************************/ |
1479 | | |
1480 | | std::vector<std::string> MEMGroup::GetMDArrayNames(CSLConstList) const |
1481 | 0 | { |
1482 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1483 | 0 | return {}; |
1484 | 0 | std::vector<std::string> names; |
1485 | 0 | for (const auto &iter : m_oMapMDArrays) |
1486 | 0 | names.push_back(iter.first); |
1487 | 0 | return names; |
1488 | 0 | } |
1489 | | |
1490 | | /************************************************************************/ |
1491 | | /* OpenMDArray() */ |
1492 | | /************************************************************************/ |
1493 | | |
1494 | | std::shared_ptr<GDALMDArray> MEMGroup::OpenMDArray(const std::string &osName, |
1495 | | CSLConstList) const |
1496 | 0 | { |
1497 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1498 | 0 | return nullptr; |
1499 | 0 | auto oIter = m_oMapMDArrays.find(osName); |
1500 | 0 | if (oIter != m_oMapMDArrays.end()) |
1501 | 0 | return oIter->second; |
1502 | 0 | return nullptr; |
1503 | 0 | } |
1504 | | |
1505 | | /************************************************************************/ |
1506 | | /* GetGroupNames() */ |
1507 | | /************************************************************************/ |
1508 | | |
1509 | | std::vector<std::string> MEMGroup::GetGroupNames(CSLConstList) const |
1510 | 0 | { |
1511 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1512 | 0 | return {}; |
1513 | 0 | std::vector<std::string> names; |
1514 | 0 | for (const auto &iter : m_oMapGroups) |
1515 | 0 | names.push_back(iter.first); |
1516 | 0 | return names; |
1517 | 0 | } |
1518 | | |
1519 | | /************************************************************************/ |
1520 | | /* OpenGroup() */ |
1521 | | /************************************************************************/ |
1522 | | |
1523 | | std::shared_ptr<GDALGroup> MEMGroup::OpenGroup(const std::string &osName, |
1524 | | CSLConstList) const |
1525 | 0 | { |
1526 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1527 | 0 | return nullptr; |
1528 | 0 | auto oIter = m_oMapGroups.find(osName); |
1529 | 0 | if (oIter != m_oMapGroups.end()) |
1530 | 0 | return oIter->second; |
1531 | 0 | return nullptr; |
1532 | 0 | } |
1533 | | |
1534 | | /************************************************************************/ |
1535 | | /* Create() */ |
1536 | | /************************************************************************/ |
1537 | | |
1538 | | /*static*/ |
1539 | | std::shared_ptr<MEMGroup> MEMGroup::Create(const std::string &osParentName, |
1540 | | const char *pszName) |
1541 | 0 | { |
1542 | 0 | auto newGroup( |
1543 | 0 | std::shared_ptr<MEMGroup>(new MEMGroup(osParentName, pszName))); |
1544 | 0 | newGroup->SetSelf(newGroup); |
1545 | 0 | if (osParentName.empty()) |
1546 | 0 | newGroup->m_poRootGroupWeak = newGroup; |
1547 | 0 | return newGroup; |
1548 | 0 | } |
1549 | | |
1550 | | /************************************************************************/ |
1551 | | /* CreateGroup() */ |
1552 | | /************************************************************************/ |
1553 | | |
1554 | | std::shared_ptr<GDALGroup> MEMGroup::CreateGroup(const std::string &osName, |
1555 | | CSLConstList /*papszOptions*/) |
1556 | 0 | { |
1557 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1558 | 0 | return nullptr; |
1559 | 0 | if (osName.empty()) |
1560 | 0 | { |
1561 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1562 | 0 | "Empty group name not supported"); |
1563 | 0 | return nullptr; |
1564 | 0 | } |
1565 | 0 | if (m_oMapGroups.find(osName) != m_oMapGroups.end()) |
1566 | 0 | { |
1567 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1568 | 0 | "A group with same name already exists"); |
1569 | 0 | return nullptr; |
1570 | 0 | } |
1571 | 0 | auto newGroup = MEMGroup::Create(GetFullName(), osName.c_str()); |
1572 | 0 | newGroup->m_pParent = std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()); |
1573 | 0 | newGroup->m_poRootGroupWeak = m_poRootGroupWeak; |
1574 | 0 | m_oMapGroups[osName] = newGroup; |
1575 | 0 | return newGroup; |
1576 | 0 | } |
1577 | | |
1578 | | /************************************************************************/ |
1579 | | /* DeleteGroup() */ |
1580 | | /************************************************************************/ |
1581 | | |
1582 | | bool MEMGroup::DeleteGroup(const std::string &osName, |
1583 | | CSLConstList /*papszOptions*/) |
1584 | 0 | { |
1585 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1586 | 0 | return false; |
1587 | 0 | auto oIter = m_oMapGroups.find(osName); |
1588 | 0 | if (oIter == m_oMapGroups.end()) |
1589 | 0 | { |
1590 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1591 | 0 | "Group %s is not a sub-group of this group", osName.c_str()); |
1592 | 0 | return false; |
1593 | 0 | } |
1594 | | |
1595 | 0 | oIter->second->Deleted(); |
1596 | 0 | m_oMapGroups.erase(oIter); |
1597 | 0 | return true; |
1598 | 0 | } |
1599 | | |
1600 | | /************************************************************************/ |
1601 | | /* NotifyChildrenOfDeletion() */ |
1602 | | /************************************************************************/ |
1603 | | |
1604 | | void MEMGroup::NotifyChildrenOfDeletion() |
1605 | 0 | { |
1606 | 0 | for (const auto &oIter : m_oMapGroups) |
1607 | 0 | oIter.second->ParentDeleted(); |
1608 | 0 | for (const auto &oIter : m_oMapMDArrays) |
1609 | 0 | oIter.second->ParentDeleted(); |
1610 | 0 | for (const auto &oIter : m_oMapAttributes) |
1611 | 0 | oIter.second->ParentDeleted(); |
1612 | 0 | for (const auto &oIter : m_oMapDimensions) |
1613 | 0 | oIter.second->ParentDeleted(); |
1614 | 0 | } |
1615 | | |
1616 | | /************************************************************************/ |
1617 | | /* CreateMDArray() */ |
1618 | | /************************************************************************/ |
1619 | | |
1620 | | std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray( |
1621 | | const std::string &osName, |
1622 | | const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions, |
1623 | | const GDALExtendedDataType &oType, void *pData, CSLConstList papszOptions) |
1624 | 0 | { |
1625 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1626 | 0 | return nullptr; |
1627 | 0 | if (osName.empty()) |
1628 | 0 | { |
1629 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1630 | 0 | "Empty array name not supported"); |
1631 | 0 | return nullptr; |
1632 | 0 | } |
1633 | 0 | if (m_oMapMDArrays.find(osName) != m_oMapMDArrays.end()) |
1634 | 0 | { |
1635 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1636 | 0 | "An array with same name already exists"); |
1637 | 0 | return nullptr; |
1638 | 0 | } |
1639 | 0 | auto newArray( |
1640 | 0 | MEMMDArray::Create(GetFullName(), osName, aoDimensions, oType)); |
1641 | |
|
1642 | 0 | GByte *pabyData = nullptr; |
1643 | 0 | std::vector<GPtrDiff_t> anStrides; |
1644 | 0 | if (pData) |
1645 | 0 | { |
1646 | 0 | pabyData = static_cast<GByte *>(pData); |
1647 | 0 | const char *pszStrides = CSLFetchNameValue(papszOptions, "STRIDES"); |
1648 | 0 | if (pszStrides) |
1649 | 0 | { |
1650 | 0 | CPLStringList aosStrides(CSLTokenizeString2(pszStrides, ",", 0)); |
1651 | 0 | if (static_cast<size_t>(aosStrides.size()) != aoDimensions.size()) |
1652 | 0 | { |
1653 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1654 | 0 | "Invalid number of strides"); |
1655 | 0 | return nullptr; |
1656 | 0 | } |
1657 | 0 | for (int i = 0; i < aosStrides.size(); i++) |
1658 | 0 | { |
1659 | 0 | const auto nStride = CPLAtoGIntBig(aosStrides[i]); |
1660 | 0 | anStrides.push_back(static_cast<GPtrDiff_t>(nStride)); |
1661 | 0 | } |
1662 | 0 | } |
1663 | 0 | } |
1664 | 0 | if (!newArray->Init(pabyData, anStrides)) |
1665 | 0 | return nullptr; |
1666 | | |
1667 | 0 | for (auto &poDim : newArray->GetDimensions()) |
1668 | 0 | { |
1669 | 0 | const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim); |
1670 | 0 | if (dim) |
1671 | 0 | dim->RegisterUsingArray(newArray.get()); |
1672 | 0 | } |
1673 | |
|
1674 | 0 | newArray->RegisterGroup(m_pSelf); |
1675 | 0 | m_oMapMDArrays[osName] = newArray; |
1676 | 0 | return newArray; |
1677 | 0 | } |
1678 | | |
1679 | | std::shared_ptr<GDALMDArray> MEMGroup::CreateMDArray( |
1680 | | const std::string &osName, |
1681 | | const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions, |
1682 | | const GDALExtendedDataType &oType, CSLConstList papszOptions) |
1683 | 0 | { |
1684 | 0 | void *pData = nullptr; |
1685 | 0 | const char *pszDataPointer = CSLFetchNameValue(papszOptions, "DATAPOINTER"); |
1686 | 0 | if (pszDataPointer) |
1687 | 0 | { |
1688 | | // Will not work on architectures with "capability pointers" |
1689 | 0 | pData = CPLScanPointer(pszDataPointer, |
1690 | 0 | static_cast<int>(strlen(pszDataPointer))); |
1691 | 0 | } |
1692 | 0 | return CreateMDArray(osName, aoDimensions, oType, pData, papszOptions); |
1693 | 0 | } |
1694 | | |
1695 | | /************************************************************************/ |
1696 | | /* DeleteMDArray() */ |
1697 | | /************************************************************************/ |
1698 | | |
1699 | | bool MEMGroup::DeleteMDArray(const std::string &osName, |
1700 | | CSLConstList /*papszOptions*/) |
1701 | 0 | { |
1702 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1703 | 0 | return false; |
1704 | 0 | auto oIter = m_oMapMDArrays.find(osName); |
1705 | 0 | if (oIter == m_oMapMDArrays.end()) |
1706 | 0 | { |
1707 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1708 | 0 | "Array %s is not an array of this group", osName.c_str()); |
1709 | 0 | return false; |
1710 | 0 | } |
1711 | | |
1712 | 0 | oIter->second->Deleted(); |
1713 | 0 | m_oMapMDArrays.erase(oIter); |
1714 | 0 | return true; |
1715 | 0 | } |
1716 | | |
1717 | | /************************************************************************/ |
1718 | | /* MEMGroupCreateMDArray() */ |
1719 | | /************************************************************************/ |
1720 | | |
1721 | | // Used by NUMPYMultiDimensionalDataset |
1722 | | std::shared_ptr<GDALMDArray> MEMGroupCreateMDArray( |
1723 | | GDALGroup *poGroup, const std::string &osName, |
1724 | | const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions, |
1725 | | const GDALExtendedDataType &oDataType, void *pData, |
1726 | | CSLConstList papszOptions) |
1727 | 0 | { |
1728 | 0 | auto poMemGroup = dynamic_cast<MEMGroup *>(poGroup); |
1729 | 0 | if (!poMemGroup) |
1730 | 0 | { |
1731 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1732 | 0 | "MEMGroupCreateMDArray(): poGroup not of type MEMGroup"); |
1733 | 0 | return nullptr; |
1734 | 0 | } |
1735 | 0 | return poMemGroup->CreateMDArray(osName, aoDimensions, oDataType, pData, |
1736 | 0 | papszOptions); |
1737 | 0 | } |
1738 | | |
1739 | | /************************************************************************/ |
1740 | | /* GetAttribute() */ |
1741 | | /************************************************************************/ |
1742 | | |
1743 | | std::shared_ptr<GDALAttribute> |
1744 | | MEMGroup::GetAttribute(const std::string &osName) const |
1745 | 0 | { |
1746 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1747 | 0 | return nullptr; |
1748 | 0 | auto oIter = m_oMapAttributes.find(osName); |
1749 | 0 | if (oIter != m_oMapAttributes.end()) |
1750 | 0 | return oIter->second; |
1751 | 0 | return nullptr; |
1752 | 0 | } |
1753 | | |
1754 | | /************************************************************************/ |
1755 | | /* GetAttributes() */ |
1756 | | /************************************************************************/ |
1757 | | |
1758 | | std::vector<std::shared_ptr<GDALAttribute>> |
1759 | | MEMGroup::GetAttributes(CSLConstList) const |
1760 | 0 | { |
1761 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1762 | 0 | return {}; |
1763 | 0 | std::vector<std::shared_ptr<GDALAttribute>> oRes; |
1764 | 0 | for (const auto &oIter : m_oMapAttributes) |
1765 | 0 | { |
1766 | 0 | oRes.push_back(oIter.second); |
1767 | 0 | } |
1768 | 0 | return oRes; |
1769 | 0 | } |
1770 | | |
1771 | | /************************************************************************/ |
1772 | | /* GetDimensions() */ |
1773 | | /************************************************************************/ |
1774 | | |
1775 | | std::vector<std::shared_ptr<GDALDimension>> |
1776 | | MEMGroup::GetDimensions(CSLConstList) const |
1777 | 0 | { |
1778 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1779 | 0 | return {}; |
1780 | 0 | std::vector<std::shared_ptr<GDALDimension>> oRes; |
1781 | 0 | for (const auto &oIter : m_oMapDimensions) |
1782 | 0 | { |
1783 | 0 | oRes.push_back(oIter.second); |
1784 | 0 | } |
1785 | 0 | return oRes; |
1786 | 0 | } |
1787 | | |
1788 | | /************************************************************************/ |
1789 | | /* CreateAttribute() */ |
1790 | | /************************************************************************/ |
1791 | | |
1792 | | std::shared_ptr<GDALAttribute> |
1793 | | MEMGroup::CreateAttribute(const std::string &osName, |
1794 | | const std::vector<GUInt64> &anDimensions, |
1795 | | const GDALExtendedDataType &oDataType, CSLConstList) |
1796 | 0 | { |
1797 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1798 | 0 | return nullptr; |
1799 | 0 | if (osName.empty()) |
1800 | 0 | { |
1801 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1802 | 0 | "Empty attribute name not supported"); |
1803 | 0 | return nullptr; |
1804 | 0 | } |
1805 | 0 | if (m_oMapAttributes.find(osName) != m_oMapAttributes.end()) |
1806 | 0 | { |
1807 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1808 | 0 | "An attribute with same name already exists"); |
1809 | 0 | return nullptr; |
1810 | 0 | } |
1811 | 0 | auto newAttr(MEMAttribute::Create( |
1812 | 0 | std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName, |
1813 | 0 | anDimensions, oDataType)); |
1814 | 0 | if (!newAttr) |
1815 | 0 | return nullptr; |
1816 | 0 | m_oMapAttributes[osName] = newAttr; |
1817 | 0 | return newAttr; |
1818 | 0 | } |
1819 | | |
1820 | | /************************************************************************/ |
1821 | | /* DeleteAttribute() */ |
1822 | | /************************************************************************/ |
1823 | | |
1824 | | bool MEMGroup::DeleteAttribute(const std::string &osName, |
1825 | | CSLConstList /*papszOptions*/) |
1826 | 0 | { |
1827 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1828 | 0 | return false; |
1829 | 0 | auto oIter = m_oMapAttributes.find(osName); |
1830 | 0 | if (oIter == m_oMapAttributes.end()) |
1831 | 0 | { |
1832 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1833 | 0 | "Attribute %s is not an attribute of this group", |
1834 | 0 | osName.c_str()); |
1835 | 0 | return false; |
1836 | 0 | } |
1837 | | |
1838 | 0 | oIter->second->Deleted(); |
1839 | 0 | m_oMapAttributes.erase(oIter); |
1840 | 0 | return true; |
1841 | 0 | } |
1842 | | |
1843 | | /************************************************************************/ |
1844 | | /* Rename() */ |
1845 | | /************************************************************************/ |
1846 | | |
1847 | | bool MEMGroup::Rename(const std::string &osNewName) |
1848 | 0 | { |
1849 | 0 | if (!CheckValidAndErrorOutIfNot()) |
1850 | 0 | return false; |
1851 | 0 | if (osNewName.empty()) |
1852 | 0 | { |
1853 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported"); |
1854 | 0 | return false; |
1855 | 0 | } |
1856 | 0 | if (m_osName == "/") |
1857 | 0 | { |
1858 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Cannot rename root group"); |
1859 | 0 | return false; |
1860 | 0 | } |
1861 | 0 | auto pParent = m_pParent.lock(); |
1862 | 0 | if (pParent) |
1863 | 0 | { |
1864 | 0 | if (pParent->m_oMapGroups.find(osNewName) != |
1865 | 0 | pParent->m_oMapGroups.end()) |
1866 | 0 | { |
1867 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1868 | 0 | "A group with same name already exists"); |
1869 | 0 | return false; |
1870 | 0 | } |
1871 | 0 | pParent->m_oMapGroups.erase(pParent->m_oMapGroups.find(m_osName)); |
1872 | 0 | } |
1873 | | |
1874 | 0 | BaseRename(osNewName); |
1875 | |
|
1876 | 0 | if (pParent) |
1877 | 0 | { |
1878 | 0 | CPLAssert(m_pSelf.lock()); |
1879 | 0 | pParent->m_oMapGroups[m_osName] = m_pSelf.lock(); |
1880 | 0 | } |
1881 | | |
1882 | 0 | return true; |
1883 | 0 | } |
1884 | | |
1885 | | /************************************************************************/ |
1886 | | /* NotifyChildrenOfRenaming() */ |
1887 | | /************************************************************************/ |
1888 | | |
1889 | | void MEMGroup::NotifyChildrenOfRenaming() |
1890 | 0 | { |
1891 | 0 | for (const auto &oIter : m_oMapGroups) |
1892 | 0 | oIter.second->ParentRenamed(m_osFullName); |
1893 | 0 | for (const auto &oIter : m_oMapMDArrays) |
1894 | 0 | oIter.second->ParentRenamed(m_osFullName); |
1895 | 0 | for (const auto &oIter : m_oMapAttributes) |
1896 | 0 | oIter.second->ParentRenamed(m_osFullName); |
1897 | 0 | for (const auto &oIter : m_oMapDimensions) |
1898 | 0 | oIter.second->ParentRenamed(m_osFullName); |
1899 | 0 | } |
1900 | | |
1901 | | /************************************************************************/ |
1902 | | /* RenameDimension() */ |
1903 | | /************************************************************************/ |
1904 | | |
1905 | | bool MEMGroup::RenameDimension(const std::string &osOldName, |
1906 | | const std::string &osNewName) |
1907 | 0 | { |
1908 | 0 | if (m_oMapDimensions.find(osNewName) != m_oMapDimensions.end()) |
1909 | 0 | { |
1910 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1911 | 0 | "A dimension with same name already exists"); |
1912 | 0 | return false; |
1913 | 0 | } |
1914 | 0 | auto oIter = m_oMapDimensions.find(osOldName); |
1915 | 0 | if (oIter == m_oMapDimensions.end()) |
1916 | 0 | { |
1917 | 0 | CPLAssert(false); |
1918 | 0 | return false; |
1919 | 0 | } |
1920 | 0 | auto poDim = std::move(oIter->second); |
1921 | 0 | m_oMapDimensions.erase(oIter); |
1922 | 0 | m_oMapDimensions[osNewName] = std::move(poDim); |
1923 | 0 | return true; |
1924 | 0 | } |
1925 | | |
1926 | | /************************************************************************/ |
1927 | | /* RenameArray() */ |
1928 | | /************************************************************************/ |
1929 | | |
1930 | | bool MEMGroup::RenameArray(const std::string &osOldName, |
1931 | | const std::string &osNewName) |
1932 | 0 | { |
1933 | 0 | if (m_oMapMDArrays.find(osNewName) != m_oMapMDArrays.end()) |
1934 | 0 | { |
1935 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1936 | 0 | "An array with same name already exists"); |
1937 | 0 | return false; |
1938 | 0 | } |
1939 | 0 | auto oIter = m_oMapMDArrays.find(osOldName); |
1940 | 0 | if (oIter == m_oMapMDArrays.end()) |
1941 | 0 | { |
1942 | 0 | CPLAssert(false); |
1943 | 0 | return false; |
1944 | 0 | } |
1945 | 0 | auto poArray = std::move(oIter->second); |
1946 | 0 | m_oMapMDArrays.erase(oIter); |
1947 | 0 | m_oMapMDArrays[osNewName] = std::move(poArray); |
1948 | 0 | return true; |
1949 | 0 | } |
1950 | | |
1951 | | /************************************************************************/ |
1952 | | /* MEMAbstractMDArray() */ |
1953 | | /************************************************************************/ |
1954 | | |
1955 | | MEMAbstractMDArray::MEMAbstractMDArray( |
1956 | | const std::string &osParentName, const std::string &osName, |
1957 | | const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions, |
1958 | | const GDALExtendedDataType &oType) |
1959 | 0 | : GDALAbstractMDArray(osParentName, osName), m_aoDims(aoDimensions), |
1960 | 0 | m_oType(oType) |
1961 | 0 | { |
1962 | 0 | } Unexecuted instantiation: MEMAbstractMDArray::MEMAbstractMDArray(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::shared_ptr<GDALDimension>, std::__1::allocator<std::__1::shared_ptr<GDALDimension> > > const&, GDALExtendedDataType const&) Unexecuted instantiation: MEMAbstractMDArray::MEMAbstractMDArray(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::shared_ptr<GDALDimension>, std::__1::allocator<std::__1::shared_ptr<GDALDimension> > > const&, GDALExtendedDataType const&) |
1963 | | |
1964 | | /************************************************************************/ |
1965 | | /* ~MEMAbstractMDArray() */ |
1966 | | /************************************************************************/ |
1967 | | |
1968 | | MEMAbstractMDArray::~MEMAbstractMDArray() |
1969 | 0 | { |
1970 | 0 | FreeArray(); |
1971 | 0 | } |
1972 | | |
1973 | | /************************************************************************/ |
1974 | | /* FreeArray() */ |
1975 | | /************************************************************************/ |
1976 | | |
1977 | | void MEMAbstractMDArray::FreeArray() |
1978 | 0 | { |
1979 | 0 | if (m_bOwnArray) |
1980 | 0 | { |
1981 | 0 | if (m_oType.NeedsFreeDynamicMemory()) |
1982 | 0 | { |
1983 | 0 | GByte *pabyPtr = m_pabyArray; |
1984 | 0 | GByte *pabyEnd = m_pabyArray + m_nTotalSize; |
1985 | 0 | const auto nDTSize(m_oType.GetSize()); |
1986 | 0 | while (pabyPtr < pabyEnd) |
1987 | 0 | { |
1988 | 0 | m_oType.FreeDynamicMemory(pabyPtr); |
1989 | 0 | pabyPtr += nDTSize; |
1990 | 0 | } |
1991 | 0 | } |
1992 | 0 | VSIFree(m_pabyArray); |
1993 | 0 | m_pabyArray = nullptr; |
1994 | 0 | m_nTotalSize = 0; |
1995 | 0 | m_bOwnArray = false; |
1996 | 0 | } |
1997 | 0 | } |
1998 | | |
1999 | | /************************************************************************/ |
2000 | | /* Init() */ |
2001 | | /************************************************************************/ |
2002 | | |
2003 | | bool MEMAbstractMDArray::Init(GByte *pData, |
2004 | | const std::vector<GPtrDiff_t> &anStrides) |
2005 | 0 | { |
2006 | 0 | GUInt64 nTotalSize = m_oType.GetSize(); |
2007 | 0 | if (!m_aoDims.empty()) |
2008 | 0 | { |
2009 | 0 | if (anStrides.empty()) |
2010 | 0 | { |
2011 | 0 | m_anStrides.resize(m_aoDims.size()); |
2012 | 0 | } |
2013 | 0 | else |
2014 | 0 | { |
2015 | 0 | CPLAssert(anStrides.size() == m_aoDims.size()); |
2016 | 0 | m_anStrides = anStrides; |
2017 | 0 | } |
2018 | | |
2019 | | // To compute strides we must proceed from the fastest varying dimension |
2020 | | // (the last one), and then reverse the result |
2021 | 0 | for (size_t i = m_aoDims.size(); i != 0;) |
2022 | 0 | { |
2023 | 0 | --i; |
2024 | 0 | const auto &poDim = m_aoDims[i]; |
2025 | 0 | auto nDimSize = poDim->GetSize(); |
2026 | 0 | if (nDimSize == 0) |
2027 | 0 | { |
2028 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
2029 | 0 | "Illegal dimension size 0"); |
2030 | 0 | return false; |
2031 | 0 | } |
2032 | 0 | if (nTotalSize > std::numeric_limits<GUInt64>::max() / nDimSize) |
2033 | 0 | { |
2034 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation"); |
2035 | 0 | return false; |
2036 | 0 | } |
2037 | 0 | auto nNewSize = nTotalSize * nDimSize; |
2038 | 0 | if (anStrides.empty()) |
2039 | 0 | m_anStrides[i] = static_cast<size_t>(nTotalSize); |
2040 | 0 | nTotalSize = nNewSize; |
2041 | 0 | } |
2042 | 0 | } |
2043 | | |
2044 | | // We restrict the size of the allocation so that all elements can be |
2045 | | // indexed by GPtrDiff_t |
2046 | 0 | if (nTotalSize > |
2047 | 0 | static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max())) |
2048 | 0 | { |
2049 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation"); |
2050 | 0 | return false; |
2051 | 0 | } |
2052 | 0 | m_nTotalSize = static_cast<size_t>(nTotalSize); |
2053 | 0 | if (pData) |
2054 | 0 | { |
2055 | 0 | m_pabyArray = pData; |
2056 | 0 | } |
2057 | 0 | else |
2058 | 0 | { |
2059 | 0 | m_pabyArray = static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, m_nTotalSize)); |
2060 | 0 | m_bOwnArray = true; |
2061 | 0 | } |
2062 | |
|
2063 | 0 | return m_pabyArray != nullptr; |
2064 | 0 | } |
2065 | | |
2066 | | /************************************************************************/ |
2067 | | /* FastCopy() */ |
2068 | | /************************************************************************/ |
2069 | | |
2070 | | template <int N> |
2071 | | inline static void FastCopy(size_t nIters, GByte *dstPtr, const GByte *srcPtr, |
2072 | | GPtrDiff_t dst_inc_offset, |
2073 | | GPtrDiff_t src_inc_offset) |
2074 | 0 | { |
2075 | 0 | if (nIters >= 8) |
2076 | 0 | { |
2077 | 0 | #define COPY_ELT(i) \ |
2078 | 0 | memcpy(dstPtr + (i)*dst_inc_offset, srcPtr + (i)*src_inc_offset, N) |
2079 | 0 | while (true) |
2080 | 0 | { |
2081 | 0 | COPY_ELT(0); |
2082 | 0 | COPY_ELT(1); |
2083 | 0 | COPY_ELT(2); |
2084 | 0 | COPY_ELT(3); |
2085 | 0 | COPY_ELT(4); |
2086 | 0 | COPY_ELT(5); |
2087 | 0 | COPY_ELT(6); |
2088 | 0 | COPY_ELT(7); |
2089 | 0 | nIters -= 8; |
2090 | 0 | srcPtr += 8 * src_inc_offset; |
2091 | 0 | dstPtr += 8 * dst_inc_offset; |
2092 | 0 | if (nIters < 8) |
2093 | 0 | break; |
2094 | 0 | } |
2095 | 0 | if (nIters == 0) |
2096 | 0 | return; |
2097 | 0 | } |
2098 | 0 | while (true) |
2099 | 0 | { |
2100 | 0 | memcpy(dstPtr, srcPtr, N); |
2101 | 0 | if ((--nIters) == 0) |
2102 | 0 | break; |
2103 | 0 | srcPtr += src_inc_offset; |
2104 | 0 | dstPtr += dst_inc_offset; |
2105 | 0 | } |
2106 | 0 | } Unexecuted instantiation: memdataset.cpp:void FastCopy<1>(unsigned long, unsigned char*, unsigned char const*, long long, long long) Unexecuted instantiation: memdataset.cpp:void FastCopy<2>(unsigned long, unsigned char*, unsigned char const*, long long, long long) Unexecuted instantiation: memdataset.cpp:void FastCopy<4>(unsigned long, unsigned char*, unsigned char const*, long long, long long) Unexecuted instantiation: memdataset.cpp:void FastCopy<8>(unsigned long, unsigned char*, unsigned char const*, long long, long long) Unexecuted instantiation: memdataset.cpp:void FastCopy<16>(unsigned long, unsigned char*, unsigned char const*, long long, long long) |
2107 | | |
2108 | | /************************************************************************/ |
2109 | | /* ReadWrite() */ |
2110 | | /************************************************************************/ |
2111 | | |
2112 | | void MEMAbstractMDArray::ReadWrite(bool bIsWrite, const size_t *count, |
2113 | | std::vector<StackReadWrite> &stack, |
2114 | | const GDALExtendedDataType &srcType, |
2115 | | const GDALExtendedDataType &dstType) const |
2116 | 0 | { |
2117 | 0 | const auto nDims = m_aoDims.size(); |
2118 | 0 | const auto nDimsMinus1 = nDims - 1; |
2119 | 0 | const bool bBothAreNumericDT = srcType.GetClass() == GEDTC_NUMERIC && |
2120 | 0 | dstType.GetClass() == GEDTC_NUMERIC; |
2121 | 0 | const bool bSameNumericDT = |
2122 | 0 | bBothAreNumericDT && |
2123 | 0 | srcType.GetNumericDataType() == dstType.GetNumericDataType(); |
2124 | 0 | const auto nSameDTSize = bSameNumericDT ? srcType.GetSize() : 0; |
2125 | 0 | const bool bCanUseMemcpyLastDim = |
2126 | 0 | bSameNumericDT && |
2127 | 0 | stack[nDimsMinus1].src_inc_offset == |
2128 | 0 | static_cast<GPtrDiff_t>(nSameDTSize) && |
2129 | 0 | stack[nDimsMinus1].dst_inc_offset == |
2130 | 0 | static_cast<GPtrDiff_t>(nSameDTSize); |
2131 | 0 | const size_t nCopySizeLastDim = |
2132 | 0 | bCanUseMemcpyLastDim ? nSameDTSize * count[nDimsMinus1] : 0; |
2133 | 0 | const bool bNeedsFreeDynamicMemory = |
2134 | 0 | bIsWrite && dstType.NeedsFreeDynamicMemory(); |
2135 | |
|
2136 | 0 | auto lambdaLastDim = [&](size_t idxPtr) |
2137 | 0 | { |
2138 | 0 | auto srcPtr = stack[idxPtr].src_ptr; |
2139 | 0 | auto dstPtr = stack[idxPtr].dst_ptr; |
2140 | 0 | if (nCopySizeLastDim) |
2141 | 0 | { |
2142 | 0 | memcpy(dstPtr, srcPtr, nCopySizeLastDim); |
2143 | 0 | } |
2144 | 0 | else |
2145 | 0 | { |
2146 | 0 | size_t nIters = count[nDimsMinus1]; |
2147 | 0 | const auto dst_inc_offset = stack[nDimsMinus1].dst_inc_offset; |
2148 | 0 | const auto src_inc_offset = stack[nDimsMinus1].src_inc_offset; |
2149 | 0 | if (bSameNumericDT) |
2150 | 0 | { |
2151 | 0 | if (nSameDTSize == 1) |
2152 | 0 | { |
2153 | 0 | FastCopy<1>(nIters, dstPtr, srcPtr, dst_inc_offset, |
2154 | 0 | src_inc_offset); |
2155 | 0 | return; |
2156 | 0 | } |
2157 | 0 | if (nSameDTSize == 2) |
2158 | 0 | { |
2159 | 0 | FastCopy<2>(nIters, dstPtr, srcPtr, dst_inc_offset, |
2160 | 0 | src_inc_offset); |
2161 | 0 | return; |
2162 | 0 | } |
2163 | 0 | if (nSameDTSize == 4) |
2164 | 0 | { |
2165 | 0 | FastCopy<4>(nIters, dstPtr, srcPtr, dst_inc_offset, |
2166 | 0 | src_inc_offset); |
2167 | 0 | return; |
2168 | 0 | } |
2169 | 0 | if (nSameDTSize == 8) |
2170 | 0 | { |
2171 | 0 | FastCopy<8>(nIters, dstPtr, srcPtr, dst_inc_offset, |
2172 | 0 | src_inc_offset); |
2173 | 0 | return; |
2174 | 0 | } |
2175 | 0 | if (nSameDTSize == 16) |
2176 | 0 | { |
2177 | 0 | FastCopy<16>(nIters, dstPtr, srcPtr, dst_inc_offset, |
2178 | 0 | src_inc_offset); |
2179 | 0 | return; |
2180 | 0 | } |
2181 | 0 | CPLAssert(false); |
2182 | 0 | } |
2183 | 0 | else if (bBothAreNumericDT |
2184 | 0 | #if SIZEOF_VOIDP >= 8 |
2185 | 0 | && src_inc_offset <= std::numeric_limits<int>::max() && |
2186 | 0 | dst_inc_offset <= std::numeric_limits<int>::max() |
2187 | 0 | #endif |
2188 | 0 | ) |
2189 | 0 | { |
2190 | 0 | GDALCopyWords64(srcPtr, srcType.GetNumericDataType(), |
2191 | 0 | static_cast<int>(src_inc_offset), dstPtr, |
2192 | 0 | dstType.GetNumericDataType(), |
2193 | 0 | static_cast<int>(dst_inc_offset), |
2194 | 0 | static_cast<GPtrDiff_t>(nIters)); |
2195 | 0 | return; |
2196 | 0 | } |
2197 | | |
2198 | 0 | while (true) |
2199 | 0 | { |
2200 | 0 | if (bNeedsFreeDynamicMemory) |
2201 | 0 | { |
2202 | 0 | dstType.FreeDynamicMemory(dstPtr); |
2203 | 0 | } |
2204 | 0 | GDALExtendedDataType::CopyValue(srcPtr, srcType, dstPtr, |
2205 | 0 | dstType); |
2206 | 0 | if ((--nIters) == 0) |
2207 | 0 | break; |
2208 | 0 | srcPtr += src_inc_offset; |
2209 | 0 | dstPtr += dst_inc_offset; |
2210 | 0 | } |
2211 | 0 | } |
2212 | 0 | }; |
2213 | |
|
2214 | 0 | if (nDims == 1) |
2215 | 0 | { |
2216 | 0 | lambdaLastDim(0); |
2217 | 0 | } |
2218 | 0 | else if (nDims == 2) |
2219 | 0 | { |
2220 | 0 | auto nIters = count[0]; |
2221 | 0 | while (true) |
2222 | 0 | { |
2223 | 0 | lambdaLastDim(0); |
2224 | 0 | if ((--nIters) == 0) |
2225 | 0 | break; |
2226 | 0 | stack[0].src_ptr += stack[0].src_inc_offset; |
2227 | 0 | stack[0].dst_ptr += stack[0].dst_inc_offset; |
2228 | 0 | } |
2229 | 0 | } |
2230 | 0 | else if (nDims == 3) |
2231 | 0 | { |
2232 | 0 | stack[0].nIters = count[0]; |
2233 | 0 | while (true) |
2234 | 0 | { |
2235 | 0 | stack[1].src_ptr = stack[0].src_ptr; |
2236 | 0 | stack[1].dst_ptr = stack[0].dst_ptr; |
2237 | 0 | auto nIters = count[1]; |
2238 | 0 | while (true) |
2239 | 0 | { |
2240 | 0 | lambdaLastDim(1); |
2241 | 0 | if ((--nIters) == 0) |
2242 | 0 | break; |
2243 | 0 | stack[1].src_ptr += stack[1].src_inc_offset; |
2244 | 0 | stack[1].dst_ptr += stack[1].dst_inc_offset; |
2245 | 0 | } |
2246 | 0 | if ((--stack[0].nIters) == 0) |
2247 | 0 | break; |
2248 | 0 | stack[0].src_ptr += stack[0].src_inc_offset; |
2249 | 0 | stack[0].dst_ptr += stack[0].dst_inc_offset; |
2250 | 0 | } |
2251 | 0 | } |
2252 | 0 | else |
2253 | 0 | { |
2254 | | // Implementation valid for nDims >= 3 |
2255 | |
|
2256 | 0 | size_t dimIdx = 0; |
2257 | | // Non-recursive implementation. Hence the gotos |
2258 | | // It might be possible to rewrite this without gotos, but I find they |
2259 | | // make it clearer to understand the recursive nature of the code |
2260 | 0 | lbl_next_depth: |
2261 | 0 | if (dimIdx == nDimsMinus1 - 1) |
2262 | 0 | { |
2263 | 0 | auto nIters = count[dimIdx]; |
2264 | 0 | while (true) |
2265 | 0 | { |
2266 | 0 | lambdaLastDim(dimIdx); |
2267 | 0 | if ((--nIters) == 0) |
2268 | 0 | break; |
2269 | 0 | stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset; |
2270 | 0 | stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset; |
2271 | 0 | } |
2272 | | // If there was a test if( dimIdx > 0 ), that would be valid for |
2273 | | // nDims == 2 |
2274 | 0 | goto lbl_return_to_caller; |
2275 | 0 | } |
2276 | 0 | else |
2277 | 0 | { |
2278 | 0 | stack[dimIdx].nIters = count[dimIdx]; |
2279 | 0 | while (true) |
2280 | 0 | { |
2281 | 0 | dimIdx++; |
2282 | 0 | stack[dimIdx].src_ptr = stack[dimIdx - 1].src_ptr; |
2283 | 0 | stack[dimIdx].dst_ptr = stack[dimIdx - 1].dst_ptr; |
2284 | 0 | goto lbl_next_depth; |
2285 | 0 | lbl_return_to_caller: |
2286 | 0 | dimIdx--; |
2287 | 0 | if ((--stack[dimIdx].nIters) == 0) |
2288 | 0 | break; |
2289 | 0 | stack[dimIdx].src_ptr += stack[dimIdx].src_inc_offset; |
2290 | 0 | stack[dimIdx].dst_ptr += stack[dimIdx].dst_inc_offset; |
2291 | 0 | } |
2292 | 0 | if (dimIdx > 0) |
2293 | 0 | goto lbl_return_to_caller; |
2294 | 0 | } |
2295 | 0 | } |
2296 | 0 | } |
2297 | | |
2298 | | /************************************************************************/ |
2299 | | /* IRead() */ |
2300 | | /************************************************************************/ |
2301 | | |
2302 | | bool MEMAbstractMDArray::IRead(const GUInt64 *arrayStartIdx, |
2303 | | const size_t *count, const GInt64 *arrayStep, |
2304 | | const GPtrDiff_t *bufferStride, |
2305 | | const GDALExtendedDataType &bufferDataType, |
2306 | | void *pDstBuffer) const |
2307 | 0 | { |
2308 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2309 | 0 | return false; |
2310 | | |
2311 | 0 | const auto nDims = m_aoDims.size(); |
2312 | 0 | if (nDims == 0) |
2313 | 0 | { |
2314 | 0 | GDALExtendedDataType::CopyValue(m_pabyArray, m_oType, pDstBuffer, |
2315 | 0 | bufferDataType); |
2316 | 0 | return true; |
2317 | 0 | } |
2318 | 0 | std::vector<StackReadWrite> stack(nDims); |
2319 | 0 | const auto nBufferDTSize = bufferDataType.GetSize(); |
2320 | 0 | GPtrDiff_t startSrcOffset = 0; |
2321 | 0 | for (size_t i = 0; i < nDims; i++) |
2322 | 0 | { |
2323 | 0 | startSrcOffset += |
2324 | 0 | static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]); |
2325 | 0 | stack[i].src_inc_offset = |
2326 | 0 | static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]); |
2327 | 0 | stack[i].dst_inc_offset = |
2328 | 0 | static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize); |
2329 | 0 | } |
2330 | 0 | stack[0].src_ptr = m_pabyArray + startSrcOffset; |
2331 | 0 | stack[0].dst_ptr = static_cast<GByte *>(pDstBuffer); |
2332 | |
|
2333 | 0 | ReadWrite(false, count, stack, m_oType, bufferDataType); |
2334 | 0 | return true; |
2335 | 0 | } |
2336 | | |
2337 | | /************************************************************************/ |
2338 | | /* IWrite() */ |
2339 | | /************************************************************************/ |
2340 | | |
2341 | | bool MEMAbstractMDArray::IWrite(const GUInt64 *arrayStartIdx, |
2342 | | const size_t *count, const GInt64 *arrayStep, |
2343 | | const GPtrDiff_t *bufferStride, |
2344 | | const GDALExtendedDataType &bufferDataType, |
2345 | | const void *pSrcBuffer) |
2346 | 0 | { |
2347 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2348 | 0 | return false; |
2349 | 0 | if (!m_bWritable) |
2350 | 0 | { |
2351 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Non updatable object"); |
2352 | 0 | return false; |
2353 | 0 | } |
2354 | | |
2355 | 0 | m_bModified = true; |
2356 | |
|
2357 | 0 | const auto nDims = m_aoDims.size(); |
2358 | 0 | if (nDims == 0) |
2359 | 0 | { |
2360 | 0 | m_oType.FreeDynamicMemory(m_pabyArray); |
2361 | 0 | GDALExtendedDataType::CopyValue(pSrcBuffer, bufferDataType, m_pabyArray, |
2362 | 0 | m_oType); |
2363 | 0 | return true; |
2364 | 0 | } |
2365 | 0 | std::vector<StackReadWrite> stack(nDims); |
2366 | 0 | const auto nBufferDTSize = bufferDataType.GetSize(); |
2367 | 0 | GPtrDiff_t startDstOffset = 0; |
2368 | 0 | for (size_t i = 0; i < nDims; i++) |
2369 | 0 | { |
2370 | 0 | startDstOffset += |
2371 | 0 | static_cast<GPtrDiff_t>(arrayStartIdx[i] * m_anStrides[i]); |
2372 | 0 | stack[i].dst_inc_offset = |
2373 | 0 | static_cast<GPtrDiff_t>(arrayStep[i] * m_anStrides[i]); |
2374 | 0 | stack[i].src_inc_offset = |
2375 | 0 | static_cast<GPtrDiff_t>(bufferStride[i] * nBufferDTSize); |
2376 | 0 | } |
2377 | |
|
2378 | 0 | stack[0].dst_ptr = m_pabyArray + startDstOffset; |
2379 | 0 | stack[0].src_ptr = static_cast<const GByte *>(pSrcBuffer); |
2380 | |
|
2381 | 0 | ReadWrite(true, count, stack, bufferDataType, m_oType); |
2382 | 0 | return true; |
2383 | 0 | } |
2384 | | |
2385 | | /************************************************************************/ |
2386 | | /* MEMMDArray() */ |
2387 | | /************************************************************************/ |
2388 | | |
2389 | | MEMMDArray::MEMMDArray( |
2390 | | const std::string &osParentName, const std::string &osName, |
2391 | | const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions, |
2392 | | const GDALExtendedDataType &oType) |
2393 | 0 | : GDALAbstractMDArray(osParentName, osName), |
2394 | 0 | MEMAbstractMDArray(osParentName, osName, aoDimensions, oType), |
2395 | 0 | GDALMDArray(osParentName, osName) |
2396 | 0 | { |
2397 | 0 | } Unexecuted instantiation: MEMMDArray::MEMMDArray(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::shared_ptr<GDALDimension>, std::__1::allocator<std::__1::shared_ptr<GDALDimension> > > const&, GDALExtendedDataType const&) Unexecuted instantiation: MEMMDArray::MEMMDArray(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::shared_ptr<GDALDimension>, std::__1::allocator<std::__1::shared_ptr<GDALDimension> > > const&, GDALExtendedDataType const&) |
2398 | | |
2399 | | /************************************************************************/ |
2400 | | /* ~MEMMDArray() */ |
2401 | | /************************************************************************/ |
2402 | | |
2403 | | MEMMDArray::~MEMMDArray() |
2404 | 0 | { |
2405 | 0 | if (m_pabyNoData) |
2406 | 0 | { |
2407 | 0 | m_oType.FreeDynamicMemory(&m_pabyNoData[0]); |
2408 | 0 | CPLFree(m_pabyNoData); |
2409 | 0 | } |
2410 | |
|
2411 | 0 | for (auto &poDim : GetDimensions()) |
2412 | 0 | { |
2413 | 0 | const auto dim = std::dynamic_pointer_cast<MEMDimension>(poDim); |
2414 | 0 | if (dim) |
2415 | 0 | dim->UnRegisterUsingArray(this); |
2416 | 0 | } |
2417 | 0 | } |
2418 | | |
2419 | | /************************************************************************/ |
2420 | | /* GetRawNoDataValue() */ |
2421 | | /************************************************************************/ |
2422 | | |
2423 | | const void *MEMMDArray::GetRawNoDataValue() const |
2424 | 0 | { |
2425 | 0 | return m_pabyNoData; |
2426 | 0 | } |
2427 | | |
2428 | | /************************************************************************/ |
2429 | | /* SetRawNoDataValue() */ |
2430 | | /************************************************************************/ |
2431 | | |
2432 | | bool MEMMDArray::SetRawNoDataValue(const void *pNoData) |
2433 | 0 | { |
2434 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2435 | 0 | return false; |
2436 | 0 | if (m_pabyNoData) |
2437 | 0 | { |
2438 | 0 | m_oType.FreeDynamicMemory(&m_pabyNoData[0]); |
2439 | 0 | } |
2440 | |
|
2441 | 0 | if (pNoData == nullptr) |
2442 | 0 | { |
2443 | 0 | CPLFree(m_pabyNoData); |
2444 | 0 | m_pabyNoData = nullptr; |
2445 | 0 | } |
2446 | 0 | else |
2447 | 0 | { |
2448 | 0 | const auto nSize = m_oType.GetSize(); |
2449 | 0 | if (m_pabyNoData == nullptr) |
2450 | 0 | { |
2451 | 0 | m_pabyNoData = static_cast<GByte *>(CPLMalloc(nSize)); |
2452 | 0 | } |
2453 | 0 | memset(m_pabyNoData, 0, nSize); |
2454 | 0 | GDALExtendedDataType::CopyValue(pNoData, m_oType, m_pabyNoData, |
2455 | 0 | m_oType); |
2456 | 0 | } |
2457 | 0 | return true; |
2458 | 0 | } |
2459 | | |
2460 | | /************************************************************************/ |
2461 | | /* GetAttribute() */ |
2462 | | /************************************************************************/ |
2463 | | |
2464 | | std::shared_ptr<GDALAttribute> |
2465 | | MEMMDArray::GetAttribute(const std::string &osName) const |
2466 | 0 | { |
2467 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2468 | 0 | return nullptr; |
2469 | 0 | auto oIter = m_oMapAttributes.find(osName); |
2470 | 0 | if (oIter != m_oMapAttributes.end()) |
2471 | 0 | return oIter->second; |
2472 | 0 | return nullptr; |
2473 | 0 | } |
2474 | | |
2475 | | /************************************************************************/ |
2476 | | /* GetAttributes() */ |
2477 | | /************************************************************************/ |
2478 | | |
2479 | | std::vector<std::shared_ptr<GDALAttribute>> |
2480 | | MEMMDArray::GetAttributes(CSLConstList) const |
2481 | 0 | { |
2482 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2483 | 0 | return {}; |
2484 | 0 | std::vector<std::shared_ptr<GDALAttribute>> oRes; |
2485 | 0 | for (const auto &oIter : m_oMapAttributes) |
2486 | 0 | { |
2487 | 0 | oRes.push_back(oIter.second); |
2488 | 0 | } |
2489 | 0 | return oRes; |
2490 | 0 | } |
2491 | | |
2492 | | /************************************************************************/ |
2493 | | /* CreateAttribute() */ |
2494 | | /************************************************************************/ |
2495 | | |
2496 | | std::shared_ptr<GDALAttribute> |
2497 | | MEMMDArray::CreateAttribute(const std::string &osName, |
2498 | | const std::vector<GUInt64> &anDimensions, |
2499 | | const GDALExtendedDataType &oDataType, CSLConstList) |
2500 | 0 | { |
2501 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2502 | 0 | return nullptr; |
2503 | 0 | if (osName.empty()) |
2504 | 0 | { |
2505 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
2506 | 0 | "Empty attribute name not supported"); |
2507 | 0 | return nullptr; |
2508 | 0 | } |
2509 | 0 | if (m_oMapAttributes.find(osName) != m_oMapAttributes.end()) |
2510 | 0 | { |
2511 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2512 | 0 | "An attribute with same name already exists"); |
2513 | 0 | return nullptr; |
2514 | 0 | } |
2515 | 0 | auto poSelf = std::dynamic_pointer_cast<MEMMDArray>(m_pSelf.lock()); |
2516 | 0 | CPLAssert(poSelf); |
2517 | 0 | auto newAttr(MEMAttribute::Create(poSelf, osName, anDimensions, oDataType)); |
2518 | 0 | if (!newAttr) |
2519 | 0 | return nullptr; |
2520 | 0 | m_oMapAttributes[osName] = newAttr; |
2521 | 0 | return newAttr; |
2522 | 0 | } |
2523 | | |
2524 | | /************************************************************************/ |
2525 | | /* DeleteAttribute() */ |
2526 | | /************************************************************************/ |
2527 | | |
2528 | | bool MEMMDArray::DeleteAttribute(const std::string &osName, |
2529 | | CSLConstList /*papszOptions*/) |
2530 | 0 | { |
2531 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2532 | 0 | return false; |
2533 | 0 | auto oIter = m_oMapAttributes.find(osName); |
2534 | 0 | if (oIter == m_oMapAttributes.end()) |
2535 | 0 | { |
2536 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2537 | 0 | "Attribute %s is not an attribute of this array", |
2538 | 0 | osName.c_str()); |
2539 | 0 | return false; |
2540 | 0 | } |
2541 | | |
2542 | 0 | oIter->second->Deleted(); |
2543 | 0 | m_oMapAttributes.erase(oIter); |
2544 | 0 | return true; |
2545 | 0 | } |
2546 | | |
2547 | | /************************************************************************/ |
2548 | | /* GetCoordinateVariables() */ |
2549 | | /************************************************************************/ |
2550 | | |
2551 | | std::vector<std::shared_ptr<GDALMDArray>> |
2552 | | MEMMDArray::GetCoordinateVariables() const |
2553 | 0 | { |
2554 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2555 | 0 | return {}; |
2556 | 0 | std::vector<std::shared_ptr<GDALMDArray>> ret; |
2557 | 0 | const auto poCoordinates = GetAttribute("coordinates"); |
2558 | 0 | if (poCoordinates && |
2559 | 0 | poCoordinates->GetDataType().GetClass() == GEDTC_STRING && |
2560 | 0 | poCoordinates->GetDimensionCount() == 0) |
2561 | 0 | { |
2562 | 0 | const char *pszCoordinates = poCoordinates->ReadAsString(); |
2563 | 0 | if (pszCoordinates) |
2564 | 0 | { |
2565 | 0 | auto poGroup = m_poGroupWeak.lock(); |
2566 | 0 | if (!poGroup) |
2567 | 0 | { |
2568 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2569 | 0 | "Cannot access coordinate variables of %s has " |
2570 | 0 | "belonging group has gone out of scope", |
2571 | 0 | GetName().c_str()); |
2572 | 0 | } |
2573 | 0 | else |
2574 | 0 | { |
2575 | 0 | const CPLStringList aosNames( |
2576 | 0 | CSLTokenizeString2(pszCoordinates, " ", 0)); |
2577 | 0 | for (int i = 0; i < aosNames.size(); i++) |
2578 | 0 | { |
2579 | 0 | auto poCoordinateVar = poGroup->OpenMDArray(aosNames[i]); |
2580 | 0 | if (poCoordinateVar) |
2581 | 0 | { |
2582 | 0 | ret.emplace_back(poCoordinateVar); |
2583 | 0 | } |
2584 | 0 | else |
2585 | 0 | { |
2586 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
2587 | 0 | "Cannot find variable corresponding to " |
2588 | 0 | "coordinate %s", |
2589 | 0 | aosNames[i]); |
2590 | 0 | } |
2591 | 0 | } |
2592 | 0 | } |
2593 | 0 | } |
2594 | 0 | } |
2595 | |
|
2596 | 0 | return ret; |
2597 | 0 | } |
2598 | | |
2599 | | /************************************************************************/ |
2600 | | /* Resize() */ |
2601 | | /************************************************************************/ |
2602 | | |
2603 | | bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes, |
2604 | | CSLConstList /* papszOptions */) |
2605 | 0 | { |
2606 | 0 | return Resize(anNewDimSizes, /*bResizeOtherArrays=*/true); |
2607 | 0 | } |
2608 | | |
2609 | | bool MEMMDArray::Resize(const std::vector<GUInt64> &anNewDimSizes, |
2610 | | bool bResizeOtherArrays) |
2611 | 0 | { |
2612 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2613 | 0 | return false; |
2614 | 0 | if (!IsWritable()) |
2615 | 0 | { |
2616 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2617 | 0 | "Resize() not supported on read-only file"); |
2618 | 0 | return false; |
2619 | 0 | } |
2620 | 0 | if (!m_bOwnArray) |
2621 | 0 | { |
2622 | 0 | CPLError( |
2623 | 0 | CE_Failure, CPLE_AppDefined, |
2624 | 0 | "Resize() not supported on an array that does not own its memory"); |
2625 | 0 | return false; |
2626 | 0 | } |
2627 | | |
2628 | 0 | const auto nDimCount = GetDimensionCount(); |
2629 | 0 | if (anNewDimSizes.size() != nDimCount) |
2630 | 0 | { |
2631 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
2632 | 0 | "Not expected number of values in anNewDimSizes."); |
2633 | 0 | return false; |
2634 | 0 | } |
2635 | | |
2636 | 0 | auto &dims = GetDimensions(); |
2637 | 0 | std::vector<size_t> anDecreasedDimIdx; |
2638 | 0 | std::vector<size_t> anGrownDimIdx; |
2639 | 0 | std::map<GDALDimension *, GUInt64> oMapDimToSize; |
2640 | 0 | for (size_t i = 0; i < nDimCount; ++i) |
2641 | 0 | { |
2642 | 0 | auto oIter = oMapDimToSize.find(dims[i].get()); |
2643 | 0 | if (oIter != oMapDimToSize.end() && oIter->second != anNewDimSizes[i]) |
2644 | 0 | { |
2645 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2646 | 0 | "Cannot resize a dimension referenced several times " |
2647 | 0 | "to different sizes"); |
2648 | 0 | return false; |
2649 | 0 | } |
2650 | 0 | if (anNewDimSizes[i] != dims[i]->GetSize()) |
2651 | 0 | { |
2652 | 0 | if (anNewDimSizes[i] == 0) |
2653 | 0 | { |
2654 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
2655 | 0 | "Illegal dimension size 0"); |
2656 | 0 | return false; |
2657 | 0 | } |
2658 | 0 | auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]); |
2659 | 0 | if (!dim) |
2660 | 0 | { |
2661 | 0 | CPLError( |
2662 | 0 | CE_Failure, CPLE_AppDefined, |
2663 | 0 | "Cannot resize a dimension that is not a MEMDimension"); |
2664 | 0 | return false; |
2665 | 0 | } |
2666 | 0 | oMapDimToSize[dim.get()] = anNewDimSizes[i]; |
2667 | 0 | if (anNewDimSizes[i] < dims[i]->GetSize()) |
2668 | 0 | { |
2669 | 0 | anDecreasedDimIdx.push_back(i); |
2670 | 0 | } |
2671 | 0 | else |
2672 | 0 | { |
2673 | 0 | anGrownDimIdx.push_back(i); |
2674 | 0 | } |
2675 | 0 | } |
2676 | 0 | else |
2677 | 0 | { |
2678 | 0 | oMapDimToSize[dims[i].get()] = dims[i]->GetSize(); |
2679 | 0 | } |
2680 | 0 | } |
2681 | | |
2682 | 0 | const auto ResizeOtherArrays = [this, &anNewDimSizes, nDimCount, &dims]() |
2683 | 0 | { |
2684 | 0 | std::set<MEMMDArray *> oSetArrays; |
2685 | 0 | std::map<GDALDimension *, GUInt64> oMapNewSize; |
2686 | 0 | for (size_t i = 0; i < nDimCount; ++i) |
2687 | 0 | { |
2688 | 0 | if (anNewDimSizes[i] != dims[i]->GetSize()) |
2689 | 0 | { |
2690 | 0 | auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]); |
2691 | 0 | if (!dim) |
2692 | 0 | { |
2693 | 0 | CPLAssert(false); |
2694 | 0 | } |
2695 | 0 | else |
2696 | 0 | { |
2697 | 0 | oMapNewSize[dims[i].get()] = anNewDimSizes[i]; |
2698 | 0 | for (const auto &poArray : dim->GetUsingArrays()) |
2699 | 0 | { |
2700 | 0 | if (poArray != this) |
2701 | 0 | oSetArrays.insert(poArray); |
2702 | 0 | } |
2703 | 0 | } |
2704 | 0 | } |
2705 | 0 | } |
2706 | | |
2707 | 0 | bool bOK = true; |
2708 | 0 | for (auto *poArray : oSetArrays) |
2709 | 0 | { |
2710 | 0 | const auto &apoOtherDims = poArray->GetDimensions(); |
2711 | 0 | std::vector<GUInt64> anOtherArrayNewDimSizes( |
2712 | 0 | poArray->GetDimensionCount()); |
2713 | 0 | for (size_t i = 0; i < anOtherArrayNewDimSizes.size(); ++i) |
2714 | 0 | { |
2715 | 0 | auto oIter = oMapNewSize.find(apoOtherDims[i].get()); |
2716 | 0 | if (oIter != oMapNewSize.end()) |
2717 | 0 | anOtherArrayNewDimSizes[i] = oIter->second; |
2718 | 0 | else |
2719 | 0 | anOtherArrayNewDimSizes[i] = apoOtherDims[i]->GetSize(); |
2720 | 0 | } |
2721 | 0 | if (!poArray->Resize(anOtherArrayNewDimSizes, |
2722 | 0 | /*bResizeOtherArrays=*/false)) |
2723 | 0 | { |
2724 | 0 | bOK = false; |
2725 | 0 | break; |
2726 | 0 | } |
2727 | 0 | } |
2728 | 0 | if (!bOK) |
2729 | 0 | { |
2730 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2731 | 0 | "Resizing of another array referencing the same dimension " |
2732 | 0 | "as one modified on the current array failed. All arrays " |
2733 | 0 | "referencing that dimension will be invalidated."); |
2734 | 0 | Invalidate(); |
2735 | 0 | for (auto *poArray : oSetArrays) |
2736 | 0 | { |
2737 | 0 | poArray->Invalidate(); |
2738 | 0 | } |
2739 | 0 | } |
2740 | |
|
2741 | 0 | return bOK; |
2742 | 0 | }; |
2743 | | |
2744 | | // Decrease slowest varying dimension |
2745 | 0 | if (anGrownDimIdx.empty() && anDecreasedDimIdx.size() == 1 && |
2746 | 0 | anDecreasedDimIdx[0] == 0) |
2747 | 0 | { |
2748 | 0 | CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0); |
2749 | 0 | const size_t nNewTotalSize = static_cast<size_t>( |
2750 | 0 | (m_nTotalSize / dims[0]->GetSize()) * anNewDimSizes[0]); |
2751 | 0 | if (m_oType.NeedsFreeDynamicMemory()) |
2752 | 0 | { |
2753 | 0 | GByte *pabyPtr = m_pabyArray + nNewTotalSize; |
2754 | 0 | GByte *pabyEnd = m_pabyArray + m_nTotalSize; |
2755 | 0 | const auto nDTSize(m_oType.GetSize()); |
2756 | 0 | while (pabyPtr < pabyEnd) |
2757 | 0 | { |
2758 | 0 | m_oType.FreeDynamicMemory(pabyPtr); |
2759 | 0 | pabyPtr += nDTSize; |
2760 | 0 | } |
2761 | 0 | } |
2762 | | // shrinking... cannot fail, and even if it does, that's ok |
2763 | 0 | GByte *pabyArray = static_cast<GByte *>( |
2764 | 0 | VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize)); |
2765 | 0 | if (pabyArray) |
2766 | 0 | m_pabyArray = pabyArray; |
2767 | 0 | m_nTotalSize = nNewTotalSize; |
2768 | |
|
2769 | 0 | if (bResizeOtherArrays) |
2770 | 0 | { |
2771 | 0 | if (!ResizeOtherArrays()) |
2772 | 0 | return false; |
2773 | | |
2774 | 0 | auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]); |
2775 | 0 | if (dim) |
2776 | 0 | { |
2777 | 0 | dim->SetSize(anNewDimSizes[0]); |
2778 | 0 | } |
2779 | 0 | else |
2780 | 0 | { |
2781 | 0 | CPLAssert(false); |
2782 | 0 | } |
2783 | 0 | } |
2784 | 0 | return true; |
2785 | 0 | } |
2786 | | |
2787 | | // Increase slowest varying dimension |
2788 | 0 | if (anDecreasedDimIdx.empty() && anGrownDimIdx.size() == 1 && |
2789 | 0 | anGrownDimIdx[0] == 0) |
2790 | 0 | { |
2791 | 0 | CPLAssert(m_nTotalSize % dims[0]->GetSize() == 0); |
2792 | 0 | GUInt64 nNewTotalSize64 = m_nTotalSize / dims[0]->GetSize(); |
2793 | 0 | if (nNewTotalSize64 > |
2794 | 0 | std::numeric_limits<GUInt64>::max() / anNewDimSizes[0]) |
2795 | 0 | { |
2796 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation"); |
2797 | 0 | return false; |
2798 | 0 | } |
2799 | 0 | nNewTotalSize64 *= anNewDimSizes[0]; |
2800 | | // We restrict the size of the allocation so that all elements can be |
2801 | | // indexed by GPtrDiff_t |
2802 | 0 | if (nNewTotalSize64 > |
2803 | 0 | static_cast<size_t>(std::numeric_limits<GPtrDiff_t>::max())) |
2804 | 0 | { |
2805 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Too big allocation"); |
2806 | 0 | return false; |
2807 | 0 | } |
2808 | 0 | const size_t nNewTotalSize = static_cast<size_t>(nNewTotalSize64); |
2809 | 0 | GByte *pabyArray = static_cast<GByte *>( |
2810 | 0 | VSI_REALLOC_VERBOSE(m_pabyArray, nNewTotalSize)); |
2811 | 0 | if (!pabyArray) |
2812 | 0 | return false; |
2813 | 0 | memset(pabyArray + m_nTotalSize, 0, nNewTotalSize - m_nTotalSize); |
2814 | 0 | m_pabyArray = pabyArray; |
2815 | 0 | m_nTotalSize = nNewTotalSize; |
2816 | |
|
2817 | 0 | if (bResizeOtherArrays) |
2818 | 0 | { |
2819 | 0 | if (!ResizeOtherArrays()) |
2820 | 0 | return false; |
2821 | | |
2822 | 0 | auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[0]); |
2823 | 0 | if (dim) |
2824 | 0 | { |
2825 | 0 | dim->SetSize(anNewDimSizes[0]); |
2826 | 0 | } |
2827 | 0 | else |
2828 | 0 | { |
2829 | 0 | CPLAssert(false); |
2830 | 0 | } |
2831 | 0 | } |
2832 | 0 | return true; |
2833 | 0 | } |
2834 | | |
2835 | | // General case where we modify other dimensions that the first one. |
2836 | | |
2837 | | // Create dummy dimensions at the new sizes |
2838 | 0 | std::vector<std::shared_ptr<GDALDimension>> aoNewDims; |
2839 | 0 | for (size_t i = 0; i < nDimCount; ++i) |
2840 | 0 | { |
2841 | 0 | aoNewDims.emplace_back(std::make_shared<MEMDimension>( |
2842 | 0 | std::string(), dims[i]->GetName(), std::string(), std::string(), |
2843 | 0 | anNewDimSizes[i])); |
2844 | 0 | } |
2845 | | |
2846 | | // Create a temporary array |
2847 | 0 | auto poTempMDArray = |
2848 | 0 | Create(std::string(), std::string(), aoNewDims, GetDataType()); |
2849 | 0 | if (!poTempMDArray->Init()) |
2850 | 0 | return false; |
2851 | 0 | std::vector<GUInt64> arrayStartIdx(nDimCount); |
2852 | 0 | std::vector<size_t> count(nDimCount); |
2853 | 0 | std::vector<GInt64> arrayStep(nDimCount, 1); |
2854 | 0 | std::vector<GPtrDiff_t> bufferStride(nDimCount); |
2855 | 0 | for (size_t i = nDimCount; i > 0;) |
2856 | 0 | { |
2857 | 0 | --i; |
2858 | 0 | if (i == nDimCount - 1) |
2859 | 0 | bufferStride[i] = 1; |
2860 | 0 | else |
2861 | 0 | { |
2862 | 0 | bufferStride[i] = static_cast<GPtrDiff_t>(bufferStride[i + 1] * |
2863 | 0 | dims[i + 1]->GetSize()); |
2864 | 0 | } |
2865 | 0 | const auto nCount = std::min(anNewDimSizes[i], dims[i]->GetSize()); |
2866 | 0 | count[i] = static_cast<size_t>(nCount); |
2867 | 0 | } |
2868 | | // Copy the current content into the array with the new layout |
2869 | 0 | if (!poTempMDArray->Write(arrayStartIdx.data(), count.data(), |
2870 | 0 | arrayStep.data(), bufferStride.data(), |
2871 | 0 | GetDataType(), m_pabyArray)) |
2872 | 0 | { |
2873 | 0 | return false; |
2874 | 0 | } |
2875 | | |
2876 | | // Move content of the temporary array into the current array, and |
2877 | | // invalidate the temporary array |
2878 | 0 | FreeArray(); |
2879 | 0 | m_bOwnArray = true; |
2880 | 0 | m_pabyArray = poTempMDArray->m_pabyArray; |
2881 | 0 | m_nTotalSize = poTempMDArray->m_nTotalSize; |
2882 | 0 | m_anStrides = poTempMDArray->m_anStrides; |
2883 | |
|
2884 | 0 | poTempMDArray->m_bOwnArray = false; |
2885 | 0 | poTempMDArray->m_pabyArray = nullptr; |
2886 | 0 | poTempMDArray->m_nTotalSize = 0; |
2887 | |
|
2888 | 0 | if (bResizeOtherArrays && !ResizeOtherArrays()) |
2889 | 0 | return false; |
2890 | | |
2891 | | // Update dimension size |
2892 | 0 | for (size_t i = 0; i < nDimCount; ++i) |
2893 | 0 | { |
2894 | 0 | if (anNewDimSizes[i] != dims[i]->GetSize()) |
2895 | 0 | { |
2896 | 0 | auto dim = std::dynamic_pointer_cast<MEMDimension>(dims[i]); |
2897 | 0 | if (dim) |
2898 | 0 | { |
2899 | 0 | dim->SetSize(anNewDimSizes[i]); |
2900 | 0 | } |
2901 | 0 | else |
2902 | 0 | { |
2903 | 0 | CPLAssert(false); |
2904 | 0 | } |
2905 | 0 | } |
2906 | 0 | } |
2907 | | |
2908 | 0 | return true; |
2909 | 0 | } |
2910 | | |
2911 | | /************************************************************************/ |
2912 | | /* Rename() */ |
2913 | | /************************************************************************/ |
2914 | | |
2915 | | bool MEMMDArray::Rename(const std::string &osNewName) |
2916 | 0 | { |
2917 | 0 | if (!CheckValidAndErrorOutIfNot()) |
2918 | 0 | return false; |
2919 | 0 | if (osNewName.empty()) |
2920 | 0 | { |
2921 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported"); |
2922 | 0 | return false; |
2923 | 0 | } |
2924 | | |
2925 | 0 | if (auto poParentGroup = |
2926 | 0 | std::dynamic_pointer_cast<MEMGroup>(m_poGroupWeak.lock())) |
2927 | 0 | { |
2928 | 0 | if (!poParentGroup->RenameArray(m_osName, osNewName)) |
2929 | 0 | { |
2930 | 0 | return false; |
2931 | 0 | } |
2932 | 0 | } |
2933 | | |
2934 | 0 | BaseRename(osNewName); |
2935 | |
|
2936 | 0 | return true; |
2937 | 0 | } |
2938 | | |
2939 | | /************************************************************************/ |
2940 | | /* NotifyChildrenOfRenaming() */ |
2941 | | /************************************************************************/ |
2942 | | |
2943 | | void MEMMDArray::NotifyChildrenOfRenaming() |
2944 | 0 | { |
2945 | 0 | for (const auto &oIter : m_oMapAttributes) |
2946 | 0 | oIter.second->ParentRenamed(m_osFullName); |
2947 | 0 | } |
2948 | | |
2949 | | /************************************************************************/ |
2950 | | /* NotifyChildrenOfDeletion() */ |
2951 | | /************************************************************************/ |
2952 | | |
2953 | | void MEMMDArray::NotifyChildrenOfDeletion() |
2954 | 0 | { |
2955 | 0 | for (const auto &oIter : m_oMapAttributes) |
2956 | 0 | oIter.second->ParentDeleted(); |
2957 | 0 | } |
2958 | | |
2959 | | /************************************************************************/ |
2960 | | /* BuildDimensions() */ |
2961 | | /************************************************************************/ |
2962 | | |
2963 | | static std::vector<std::shared_ptr<GDALDimension>> |
2964 | | BuildDimensions(const std::vector<GUInt64> &anDimensions) |
2965 | 0 | { |
2966 | 0 | std::vector<std::shared_ptr<GDALDimension>> res; |
2967 | 0 | for (size_t i = 0; i < anDimensions.size(); i++) |
2968 | 0 | { |
2969 | 0 | res.emplace_back(std::make_shared<GDALDimensionWeakIndexingVar>( |
2970 | 0 | std::string(), CPLSPrintf("dim%u", static_cast<unsigned>(i)), |
2971 | 0 | std::string(), std::string(), anDimensions[i])); |
2972 | 0 | } |
2973 | 0 | return res; |
2974 | 0 | } |
2975 | | |
2976 | | /************************************************************************/ |
2977 | | /* MEMAttribute() */ |
2978 | | /************************************************************************/ |
2979 | | |
2980 | | MEMAttribute::MEMAttribute(const std::string &osParentName, |
2981 | | const std::string &osName, |
2982 | | const std::vector<GUInt64> &anDimensions, |
2983 | | const GDALExtendedDataType &oType) |
2984 | 0 | : GDALAbstractMDArray(osParentName, osName), |
2985 | 0 | MEMAbstractMDArray(osParentName, osName, BuildDimensions(anDimensions), |
2986 | 0 | oType), |
2987 | 0 | GDALAttribute(osParentName, osName) |
2988 | 0 | { |
2989 | 0 | } Unexecuted instantiation: MEMAttribute::MEMAttribute(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<unsigned long long, std::__1::allocator<unsigned long long> > const&, GDALExtendedDataType const&) Unexecuted instantiation: MEMAttribute::MEMAttribute(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<unsigned long long, std::__1::allocator<unsigned long long> > const&, GDALExtendedDataType const&) |
2990 | | |
2991 | | /************************************************************************/ |
2992 | | /* MEMAttribute::Create() */ |
2993 | | /************************************************************************/ |
2994 | | |
2995 | | std::shared_ptr<MEMAttribute> |
2996 | | MEMAttribute::Create(const std::string &osParentName, const std::string &osName, |
2997 | | const std::vector<GUInt64> &anDimensions, |
2998 | | const GDALExtendedDataType &oType) |
2999 | 0 | { |
3000 | 0 | auto attr(std::shared_ptr<MEMAttribute>( |
3001 | 0 | new MEMAttribute(osParentName, osName, anDimensions, oType))); |
3002 | 0 | attr->SetSelf(attr); |
3003 | 0 | if (!attr->Init()) |
3004 | 0 | return nullptr; |
3005 | 0 | return attr; |
3006 | 0 | } |
3007 | | |
3008 | | /************************************************************************/ |
3009 | | /* MEMAttribute::Create() */ |
3010 | | /************************************************************************/ |
3011 | | |
3012 | | std::shared_ptr<MEMAttribute> MEMAttribute::Create( |
3013 | | const std::shared_ptr<MEMGroup> &poParentGroup, const std::string &osName, |
3014 | | const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType) |
3015 | 0 | { |
3016 | 0 | const std::string osParentName = |
3017 | 0 | (poParentGroup && poParentGroup->GetName().empty()) |
3018 | 0 | ? |
3019 | | // Case of the ZarrAttributeGroup::m_oGroup fake group |
3020 | 0 | poParentGroup->GetFullName() |
3021 | 0 | : ((poParentGroup == nullptr || poParentGroup->GetFullName() == "/" |
3022 | 0 | ? "/" |
3023 | 0 | : poParentGroup->GetFullName() + "/") + |
3024 | 0 | "_GLOBAL_"); |
3025 | 0 | auto attr(Create(osParentName, osName, anDimensions, oType)); |
3026 | 0 | if (!attr) |
3027 | 0 | return nullptr; |
3028 | 0 | attr->m_poParent = poParentGroup; |
3029 | 0 | return attr; |
3030 | 0 | } |
3031 | | |
3032 | | /************************************************************************/ |
3033 | | /* MEMAttribute::Create() */ |
3034 | | /************************************************************************/ |
3035 | | |
3036 | | std::shared_ptr<MEMAttribute> MEMAttribute::Create( |
3037 | | const std::shared_ptr<MEMMDArray> &poParentArray, const std::string &osName, |
3038 | | const std::vector<GUInt64> &anDimensions, const GDALExtendedDataType &oType) |
3039 | 0 | { |
3040 | 0 | auto attr( |
3041 | 0 | Create(poParentArray->GetFullName(), osName, anDimensions, oType)); |
3042 | 0 | if (!attr) |
3043 | 0 | return nullptr; |
3044 | 0 | attr->m_poParent = poParentArray; |
3045 | 0 | return attr; |
3046 | 0 | } |
3047 | | |
3048 | | /************************************************************************/ |
3049 | | /* Rename() */ |
3050 | | /************************************************************************/ |
3051 | | |
3052 | | bool MEMAttribute::Rename(const std::string &osNewName) |
3053 | 0 | { |
3054 | 0 | if (!CheckValidAndErrorOutIfNot()) |
3055 | 0 | return false; |
3056 | 0 | if (osNewName.empty()) |
3057 | 0 | { |
3058 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported"); |
3059 | 0 | return false; |
3060 | 0 | } |
3061 | | |
3062 | 0 | if (auto poParent = m_poParent.lock()) |
3063 | 0 | { |
3064 | 0 | if (!poParent->RenameAttribute(m_osName, osNewName)) |
3065 | 0 | { |
3066 | 0 | return false; |
3067 | 0 | } |
3068 | 0 | } |
3069 | | |
3070 | 0 | BaseRename(osNewName); |
3071 | |
|
3072 | 0 | m_bModified = true; |
3073 | |
|
3074 | 0 | return true; |
3075 | 0 | } |
3076 | | |
3077 | | /************************************************************************/ |
3078 | | /* MEMDimension() */ |
3079 | | /************************************************************************/ |
3080 | | |
3081 | | MEMDimension::MEMDimension(const std::string &osParentName, |
3082 | | const std::string &osName, const std::string &osType, |
3083 | | const std::string &osDirection, GUInt64 nSize) |
3084 | 0 | : GDALDimensionWeakIndexingVar(osParentName, osName, osType, osDirection, |
3085 | 0 | nSize) |
3086 | 0 | { |
3087 | 0 | } |
3088 | | |
3089 | | /************************************************************************/ |
3090 | | /* RegisterUsingArray() */ |
3091 | | /************************************************************************/ |
3092 | | |
3093 | | void MEMDimension::RegisterUsingArray(MEMMDArray *poArray) |
3094 | 0 | { |
3095 | 0 | m_oSetArrays.insert(poArray); |
3096 | 0 | } |
3097 | | |
3098 | | /************************************************************************/ |
3099 | | /* UnRegisterUsingArray() */ |
3100 | | /************************************************************************/ |
3101 | | |
3102 | | void MEMDimension::UnRegisterUsingArray(MEMMDArray *poArray) |
3103 | 0 | { |
3104 | 0 | m_oSetArrays.erase(poArray); |
3105 | 0 | } |
3106 | | |
3107 | | /************************************************************************/ |
3108 | | /* Create() */ |
3109 | | /************************************************************************/ |
3110 | | |
3111 | | /* static */ |
3112 | | std::shared_ptr<MEMDimension> |
3113 | | MEMDimension::Create(const std::shared_ptr<MEMGroup> &poParentGroup, |
3114 | | const std::string &osName, const std::string &osType, |
3115 | | const std::string &osDirection, GUInt64 nSize) |
3116 | 0 | { |
3117 | 0 | auto newDim(std::make_shared<MEMDimension>( |
3118 | 0 | poParentGroup->GetFullName(), osName, osType, osDirection, nSize)); |
3119 | 0 | newDim->m_poParentGroup = poParentGroup; |
3120 | 0 | return newDim; |
3121 | 0 | } |
3122 | | |
3123 | | /************************************************************************/ |
3124 | | /* CreateDimension() */ |
3125 | | /************************************************************************/ |
3126 | | |
3127 | | std::shared_ptr<GDALDimension> |
3128 | | MEMGroup::CreateDimension(const std::string &osName, const std::string &osType, |
3129 | | const std::string &osDirection, GUInt64 nSize, |
3130 | | CSLConstList) |
3131 | 0 | { |
3132 | 0 | if (osName.empty()) |
3133 | 0 | { |
3134 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
3135 | 0 | "Empty dimension name not supported"); |
3136 | 0 | return nullptr; |
3137 | 0 | } |
3138 | 0 | if (m_oMapDimensions.find(osName) != m_oMapDimensions.end()) |
3139 | 0 | { |
3140 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
3141 | 0 | "A dimension with same name already exists"); |
3142 | 0 | return nullptr; |
3143 | 0 | } |
3144 | 0 | auto newDim(MEMDimension::Create( |
3145 | 0 | std::dynamic_pointer_cast<MEMGroup>(m_pSelf.lock()), osName, osType, |
3146 | 0 | osDirection, nSize)); |
3147 | 0 | m_oMapDimensions[osName] = newDim; |
3148 | 0 | return newDim; |
3149 | 0 | } |
3150 | | |
3151 | | /************************************************************************/ |
3152 | | /* Rename() */ |
3153 | | /************************************************************************/ |
3154 | | |
3155 | | bool MEMDimension::Rename(const std::string &osNewName) |
3156 | 0 | { |
3157 | 0 | if (osNewName.empty()) |
3158 | 0 | { |
3159 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Empty name not supported"); |
3160 | 0 | return false; |
3161 | 0 | } |
3162 | | |
3163 | 0 | if (auto poParentGroup = m_poParentGroup.lock()) |
3164 | 0 | { |
3165 | 0 | if (!poParentGroup->RenameDimension(m_osName, osNewName)) |
3166 | 0 | { |
3167 | 0 | return false; |
3168 | 0 | } |
3169 | 0 | } |
3170 | | |
3171 | 0 | BaseRename(osNewName); |
3172 | |
|
3173 | 0 | return true; |
3174 | 0 | } |
3175 | | |
3176 | | /************************************************************************/ |
3177 | | /* CreateMultiDimensional() */ |
3178 | | /************************************************************************/ |
3179 | | |
3180 | | GDALDataset * |
3181 | | MEMDataset::CreateMultiDimensional(const char *pszFilename, |
3182 | | CSLConstList /*papszRootGroupOptions*/, |
3183 | | CSLConstList /*papszOptions*/) |
3184 | 0 | { |
3185 | 0 | auto poDS = new MEMDataset(); |
3186 | |
|
3187 | 0 | poDS->SetDescription(pszFilename); |
3188 | 0 | auto poRootGroup = MEMGroup::Create(std::string(), nullptr); |
3189 | 0 | poDS->m_poPrivate->m_poRootGroup = poRootGroup; |
3190 | |
|
3191 | 0 | return poDS; |
3192 | 0 | } |
3193 | | |
3194 | | /************************************************************************/ |
3195 | | /* GetRootGroup() */ |
3196 | | /************************************************************************/ |
3197 | | |
3198 | | std::shared_ptr<GDALGroup> MEMDataset::GetRootGroup() const |
3199 | 0 | { |
3200 | 0 | return m_poPrivate->m_poRootGroup; |
3201 | 0 | } |
3202 | | |
3203 | | /************************************************************************/ |
3204 | | /* MEMDatasetIdentify() */ |
3205 | | /************************************************************************/ |
3206 | | |
3207 | | static int MEMDatasetIdentify(GDALOpenInfo *poOpenInfo) |
3208 | 0 | { |
3209 | 0 | return (STARTS_WITH(poOpenInfo->pszFilename, "MEM:::") && |
3210 | 0 | poOpenInfo->fpL == nullptr); |
3211 | 0 | } |
3212 | | |
3213 | | /************************************************************************/ |
3214 | | /* MEMDatasetDelete() */ |
3215 | | /************************************************************************/ |
3216 | | |
3217 | | static CPLErr MEMDatasetDelete(const char * /* fileName */) |
3218 | 0 | { |
3219 | | /* Null implementation, so that people can Delete("MEM:::") */ |
3220 | 0 | return CE_None; |
3221 | 0 | } |
3222 | | |
3223 | | /************************************************************************/ |
3224 | | /* CreateLayer() */ |
3225 | | /************************************************************************/ |
3226 | | |
3227 | | OGRMemLayer *MEMDataset::CreateLayer(const OGRFeatureDefn &oDefn, |
3228 | | CSLConstList papszOptions) |
3229 | 0 | { |
3230 | 0 | auto poLayer = std::make_unique<OGRMemLayer>(oDefn); |
3231 | |
|
3232 | 0 | if (CPLFetchBool(papszOptions, "ADVERTIZE_UTF8", false)) |
3233 | 0 | poLayer->SetAdvertizeUTF8(true); |
3234 | |
|
3235 | 0 | poLayer->SetDataset(this); |
3236 | 0 | poLayer->SetFIDColumn(CSLFetchNameValueDef(papszOptions, "FID", "")); |
3237 | | |
3238 | | // Add layer to data source layer list. |
3239 | 0 | m_apoLayers.emplace_back(std::move(poLayer)); |
3240 | 0 | return m_apoLayers.back().get(); |
3241 | 0 | } |
3242 | | |
3243 | | /************************************************************************/ |
3244 | | /* ICreateLayer() */ |
3245 | | /************************************************************************/ |
3246 | | |
3247 | | OGRLayer *MEMDataset::ICreateLayer(const char *pszLayerName, |
3248 | | const OGRGeomFieldDefn *poGeomFieldDefn, |
3249 | | CSLConstList papszOptions) |
3250 | 0 | { |
3251 | | // Create the layer object. |
3252 | |
|
3253 | 0 | const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone; |
3254 | 0 | const auto poSRSIn = |
3255 | 0 | poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr; |
3256 | |
|
3257 | 0 | OGRSpatialReference *poSRS = nullptr; |
3258 | 0 | if (poSRSIn) |
3259 | 0 | { |
3260 | 0 | poSRS = poSRSIn->Clone(); |
3261 | 0 | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
3262 | 0 | } |
3263 | 0 | auto poLayer = std::make_unique<OGRMemLayer>(pszLayerName, poSRS, eType); |
3264 | 0 | if (poSRS) |
3265 | 0 | { |
3266 | 0 | poSRS->Release(); |
3267 | 0 | } |
3268 | |
|
3269 | 0 | if (CPLFetchBool(papszOptions, "ADVERTIZE_UTF8", false)) |
3270 | 0 | poLayer->SetAdvertizeUTF8(true); |
3271 | |
|
3272 | 0 | poLayer->SetDataset(this); |
3273 | 0 | poLayer->SetFIDColumn(CSLFetchNameValueDef(papszOptions, "FID", "")); |
3274 | | |
3275 | | // Add layer to data source layer list. |
3276 | 0 | m_apoLayers.emplace_back(std::move(poLayer)); |
3277 | 0 | return m_apoLayers.back().get(); |
3278 | 0 | } |
3279 | | |
3280 | | /************************************************************************/ |
3281 | | /* DeleteLayer() */ |
3282 | | /************************************************************************/ |
3283 | | |
3284 | | OGRErr MEMDataset::DeleteLayer(int iLayer) |
3285 | | |
3286 | 0 | { |
3287 | 0 | if (iLayer >= 0 && iLayer < static_cast<int>(m_apoLayers.size())) |
3288 | 0 | { |
3289 | 0 | m_apoLayers.erase(m_apoLayers.begin() + iLayer); |
3290 | 0 | return OGRERR_NONE; |
3291 | 0 | } |
3292 | | |
3293 | 0 | return OGRERR_FAILURE; |
3294 | 0 | } |
3295 | | |
3296 | | /************************************************************************/ |
3297 | | /* TestCapability() */ |
3298 | | /************************************************************************/ |
3299 | | |
3300 | | int MEMDataset::TestCapability(const char *pszCap) |
3301 | | |
3302 | 0 | { |
3303 | 0 | if (EQUAL(pszCap, ODsCCreateLayer)) |
3304 | 0 | return TRUE; |
3305 | 0 | else if (EQUAL(pszCap, ODsCDeleteLayer)) |
3306 | 0 | return TRUE; |
3307 | 0 | else if (EQUAL(pszCap, ODsCCreateGeomFieldAfterCreateLayer)) |
3308 | 0 | return TRUE; |
3309 | 0 | else if (EQUAL(pszCap, ODsCCurveGeometries)) |
3310 | 0 | return TRUE; |
3311 | 0 | else if (EQUAL(pszCap, ODsCMeasuredGeometries)) |
3312 | 0 | return TRUE; |
3313 | 0 | else if (EQUAL(pszCap, ODsCZGeometries)) |
3314 | 0 | return TRUE; |
3315 | 0 | else if (EQUAL(pszCap, ODsCRandomLayerWrite)) |
3316 | 0 | return TRUE; |
3317 | 0 | else if (EQUAL(pszCap, ODsCAddFieldDomain)) |
3318 | 0 | return TRUE; |
3319 | 0 | else if (EQUAL(pszCap, ODsCDeleteFieldDomain)) |
3320 | 0 | return TRUE; |
3321 | 0 | else if (EQUAL(pszCap, ODsCUpdateFieldDomain)) |
3322 | 0 | return TRUE; |
3323 | | |
3324 | 0 | return FALSE; |
3325 | 0 | } |
3326 | | |
3327 | | /************************************************************************/ |
3328 | | /* GetLayer() */ |
3329 | | /************************************************************************/ |
3330 | | |
3331 | | OGRLayer *MEMDataset::GetLayer(int iLayer) |
3332 | | |
3333 | 0 | { |
3334 | 0 | if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size())) |
3335 | 0 | return nullptr; |
3336 | | |
3337 | 0 | return m_apoLayers[iLayer].get(); |
3338 | 0 | } |
3339 | | |
3340 | | /************************************************************************/ |
3341 | | /* AddFieldDomain() */ |
3342 | | /************************************************************************/ |
3343 | | |
3344 | | bool MEMDataset::AddFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain, |
3345 | | std::string &failureReason) |
3346 | 0 | { |
3347 | 0 | if (GetFieldDomain(domain->GetName()) != nullptr) |
3348 | 0 | { |
3349 | 0 | failureReason = "A domain of identical name already exists"; |
3350 | 0 | return false; |
3351 | 0 | } |
3352 | 0 | const std::string domainName(domain->GetName()); |
3353 | 0 | m_oMapFieldDomains[domainName] = std::move(domain); |
3354 | 0 | return true; |
3355 | 0 | } |
3356 | | |
3357 | | /************************************************************************/ |
3358 | | /* DeleteFieldDomain() */ |
3359 | | /************************************************************************/ |
3360 | | |
3361 | | bool MEMDataset::DeleteFieldDomain(const std::string &name, |
3362 | | std::string &failureReason) |
3363 | 0 | { |
3364 | 0 | const auto iter = m_oMapFieldDomains.find(name); |
3365 | 0 | if (iter == m_oMapFieldDomains.end()) |
3366 | 0 | { |
3367 | 0 | failureReason = "Domain does not exist"; |
3368 | 0 | return false; |
3369 | 0 | } |
3370 | | |
3371 | 0 | m_oMapFieldDomains.erase(iter); |
3372 | |
|
3373 | 0 | for (auto &poLayer : m_apoLayers) |
3374 | 0 | { |
3375 | 0 | for (int j = 0; j < poLayer->GetLayerDefn()->GetFieldCount(); ++j) |
3376 | 0 | { |
3377 | 0 | OGRFieldDefn *poFieldDefn = |
3378 | 0 | poLayer->GetLayerDefn()->GetFieldDefn(j); |
3379 | 0 | if (poFieldDefn->GetDomainName() == name) |
3380 | 0 | { |
3381 | 0 | auto oTemporaryUnsealer(poFieldDefn->GetTemporaryUnsealer()); |
3382 | 0 | poFieldDefn->SetDomainName(std::string()); |
3383 | 0 | } |
3384 | 0 | } |
3385 | 0 | } |
3386 | |
|
3387 | 0 | return true; |
3388 | 0 | } |
3389 | | |
3390 | | /************************************************************************/ |
3391 | | /* UpdateFieldDomain() */ |
3392 | | /************************************************************************/ |
3393 | | |
3394 | | bool MEMDataset::UpdateFieldDomain(std::unique_ptr<OGRFieldDomain> &&domain, |
3395 | | std::string &failureReason) |
3396 | 0 | { |
3397 | 0 | const std::string domainName(domain->GetName()); |
3398 | 0 | const auto iter = m_oMapFieldDomains.find(domainName); |
3399 | 0 | if (iter == m_oMapFieldDomains.end()) |
3400 | 0 | { |
3401 | 0 | failureReason = "No matching domain found"; |
3402 | 0 | return false; |
3403 | 0 | } |
3404 | 0 | m_oMapFieldDomains[domainName] = std::move(domain); |
3405 | 0 | return true; |
3406 | 0 | } |
3407 | | |
3408 | | /************************************************************************/ |
3409 | | /* ExecuteSQL() */ |
3410 | | /************************************************************************/ |
3411 | | |
3412 | | OGRLayer *MEMDataset::ExecuteSQL(const char *pszStatement, |
3413 | | OGRGeometry *poSpatialFilter, |
3414 | | const char *pszDialect) |
3415 | 0 | { |
3416 | 0 | if (EQUAL(pszStatement, "PRAGMA read_only=1")) // as used by VDV driver |
3417 | 0 | { |
3418 | 0 | for (auto &poLayer : m_apoLayers) |
3419 | 0 | poLayer->SetUpdatable(false); |
3420 | 0 | return nullptr; |
3421 | 0 | } |
3422 | 0 | return GDALDataset::ExecuteSQL(pszStatement, poSpatialFilter, pszDialect); |
3423 | 0 | } |
3424 | | |
3425 | | /************************************************************************/ |
3426 | | /* GDALRegister_MEM() */ |
3427 | | /************************************************************************/ |
3428 | | |
3429 | | void GDALRegister_MEM() |
3430 | 0 | { |
3431 | 0 | auto poDM = GetGDALDriverManager(); |
3432 | 0 | if (poDM->GetDriverByName("MEM") != nullptr) |
3433 | 0 | return; |
3434 | | |
3435 | 0 | GDALDriver *poDriver = new GDALDriver(); |
3436 | |
|
3437 | 0 | poDriver->SetDescription("MEM"); |
3438 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); |
3439 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES"); |
3440 | 0 | poDriver->SetMetadataItem( |
3441 | 0 | GDAL_DMD_LONGNAME, |
3442 | 0 | "In Memory raster, vector and multidimensional raster"); |
3443 | 0 | poDriver->SetMetadataItem( |
3444 | 0 | GDAL_DMD_CREATIONDATATYPES, |
3445 | 0 | "Byte Int8 Int16 UInt16 Int32 UInt32 Int64 UInt64 Float32 Float64 " |
3446 | 0 | "CInt16 CInt32 CFloat32 CFloat64"); |
3447 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES"); |
3448 | |
|
3449 | 0 | poDriver->SetMetadataItem( |
3450 | 0 | GDAL_DMD_CREATIONOPTIONLIST, |
3451 | 0 | "<CreationOptionList>" |
3452 | 0 | " <Option name='INTERLEAVE' type='string-select' default='BAND'>" |
3453 | 0 | " <Value>BAND</Value>" |
3454 | 0 | " <Value>PIXEL</Value>" |
3455 | 0 | " </Option>" |
3456 | 0 | "</CreationOptionList>"); |
3457 | |
|
3458 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); |
3459 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); |
3460 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES"); |
3461 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); |
3462 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES"); |
3463 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES"); |
3464 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES"); |
3465 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); |
3466 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); |
3467 | 0 | poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); |
3468 | |
|
3469 | 0 | poDriver->SetMetadataItem( |
3470 | 0 | GDAL_DMD_CREATIONFIELDDATATYPES, |
3471 | 0 | "Integer Integer64 Real String Date DateTime Time IntegerList " |
3472 | 0 | "Integer64List RealList StringList Binary"); |
3473 | 0 | poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, |
3474 | 0 | "WidthPrecision Nullable Default Unique " |
3475 | 0 | "Comment AlternativeName Domain"); |
3476 | 0 | poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS, |
3477 | 0 | "Name Type WidthPrecision Nullable Default " |
3478 | 0 | "Unique Domain AlternativeName Comment"); |
3479 | |
|
3480 | 0 | poDriver->SetMetadataItem( |
3481 | 0 | GDAL_DS_LAYER_CREATIONOPTIONLIST, |
3482 | 0 | "<LayerCreationOptionList>" |
3483 | 0 | " <Option name='ADVERTIZE_UTF8' type='boolean' description='Whether " |
3484 | 0 | "the layer will contain UTF-8 strings' default='NO'/>" |
3485 | 0 | " <Option name='FID' type='string' description=" |
3486 | 0 | "'Name of the FID column to create' default='' />" |
3487 | 0 | "</LayerCreationOptionList>"); |
3488 | |
|
3489 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES"); |
3490 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); |
3491 | |
|
3492 | 0 | poDriver->SetMetadataItem(GDAL_DCAP_FIELD_DOMAINS, "YES"); |
3493 | 0 | poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES, |
3494 | 0 | "Coded Range Glob"); |
3495 | |
|
3496 | 0 | poDriver->SetMetadataItem(GDAL_DMD_ALTER_GEOM_FIELD_DEFN_FLAGS, |
3497 | 0 | "Name Type Nullable SRS CoordinateEpoch"); |
3498 | | |
3499 | | // Define GDAL_NO_OPEN_FOR_MEM_DRIVER macro to undefine Open() method for |
3500 | | // MEM driver. Otherwise, bad user input can trigger easily a GDAL crash |
3501 | | // as random pointers can be passed as a string. All code in GDAL tree |
3502 | | // using the MEM driver use the Create() method only, so Open() is not |
3503 | | // needed, except for esoteric uses. |
3504 | 0 | #ifndef GDAL_NO_OPEN_FOR_MEM_DRIVER |
3505 | 0 | poDriver->pfnOpen = MEMDataset::Open; |
3506 | 0 | poDriver->pfnIdentify = MEMDatasetIdentify; |
3507 | 0 | #endif |
3508 | 0 | poDriver->pfnCreate = MEMDataset::CreateBase; |
3509 | 0 | poDriver->pfnCreateMultiDimensional = MEMDataset::CreateMultiDimensional; |
3510 | 0 | poDriver->pfnDelete = MEMDatasetDelete; |
3511 | |
|
3512 | 0 | poDM->RegisterDriver(poDriver); |
3513 | 0 | } |