1 : /******************************************************************************
2 : * $Id: gdalproxypool.cpp 17636 2009-09-12 23:19:18Z warmerdam $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: A dataset and raster band classes that differ the opening of the
6 : * underlying dataset in a limited pool of opened datasets.
7 : * Author: Even Rouault <even dot rouault at mines dash paris dot org>
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2008, Even Rouault
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gdal_proxy.h"
32 : #include "cpl_multiproc.h"
33 :
34 : CPL_CVSID("$Id: gdalproxypool.cpp 17636 2009-09-12 23:19:18Z warmerdam $");
35 :
36 : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
37 : void** GDALGetphDLMutex();
38 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID);
39 : GIntBig GDALGetResponsiblePIDForCurrentThread();
40 :
41 : /* We *must* share the same mutex as the gdaldataset.cpp file, as we are */
42 : /* doing GDALOpen() calls that can indirectly call GDALOpenShared() on */
43 : /* an auxiliary dataset ... */
44 : /* Then we could get dead-locks in multi-threaded use case */
45 :
46 : /* ******************************************************************** */
47 : /* GDALDatasetPool */
48 : /* ******************************************************************** */
49 :
50 : /* This class is a singleton that maintains a pool of opened datasets */
51 : /* The cache uses a LRU strategy */
52 :
53 : class GDALDatasetPool;
54 : static GDALDatasetPool* singleton = NULL;
55 :
56 : struct _GDALProxyPoolCacheEntry
57 : {
58 : GIntBig responsiblePID;
59 : char *pszFileName;
60 : GDALDataset *poDS;
61 :
62 : /* Ref count of the cached dataset */
63 : int refCount;
64 :
65 : GDALProxyPoolCacheEntry* prev;
66 : GDALProxyPoolCacheEntry* next;
67 : };
68 :
69 : class GDALDatasetPool
70 : {
71 : private:
72 : /* Ref count of the pool singleton */
73 : /* Taken by "toplevel" GDALProxyPoolDataset in its constructor and released */
74 : /* in its destructor. See also refCountOfDisableRefCount for the difference */
75 : /* between toplevel and inner GDALProxyPoolDataset */
76 : int refCount;
77 :
78 : int maxSize;
79 : int currentSize;
80 : GDALProxyPoolCacheEntry* firstEntry;
81 : GDALProxyPoolCacheEntry* lastEntry;
82 :
83 : /* This variable prevents a dataset that is going to be opened in GDALDatasetPool::_RefDataset */
84 : /* from increasing refCount if, during its opening, it creates a GDALProxyPoolDataset */
85 : /* We increment it before opening or closing a cached dataset and decrement it afterwards */
86 : /* The typical use case is a VRT made of simple sources that are VRT */
87 : /* We don't want the "inner" VRT to take a reference on the pool, otherwise there is */
88 : /* a high chance that this reference will not be dropped and the pool remain ghost */
89 : int refCountOfDisableRefCount;
90 :
91 : /* Caution : to be sure that we don't run out of entries, size must be at */
92 : /* least greater or equal than the maximum number of threads */
93 : GDALDatasetPool(int maxSize);
94 : ~GDALDatasetPool();
95 : GDALProxyPoolCacheEntry* _RefDataset(const char* pszFileName, GDALAccess eAccess);
96 :
97 : void ShowContent();
98 : void CheckLinks();
99 :
100 : public:
101 : static void Ref();
102 : static void Unref();
103 : static GDALProxyPoolCacheEntry* RefDataset(const char* pszFileName, GDALAccess eAccess);
104 : static void UnrefDataset(GDALProxyPoolCacheEntry* cacheEntry);
105 : };
106 :
107 :
108 : /************************************************************************/
109 : /* GDALDatasetPool() */
110 : /************************************************************************/
111 :
112 44 : GDALDatasetPool::GDALDatasetPool(int maxSize)
113 : {
114 44 : this->maxSize = maxSize;
115 44 : currentSize = 0;
116 44 : firstEntry = NULL;
117 44 : lastEntry = NULL;
118 44 : refCount = 0;
119 44 : refCountOfDisableRefCount = 0;
120 44 : }
121 :
122 : /************************************************************************/
123 : /* ~GDALDatasetPool() */
124 : /************************************************************************/
125 :
126 44 : GDALDatasetPool::~GDALDatasetPool()
127 : {
128 44 : GDALProxyPoolCacheEntry* cur = firstEntry;
129 44 : GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
130 139 : while(cur)
131 : {
132 51 : GDALProxyPoolCacheEntry* next = cur->next;
133 51 : CPLFree(cur->pszFileName);
134 : CPLAssert(cur->refCount == 0);
135 51 : if (cur->poDS)
136 : {
137 50 : GDALSetResponsiblePIDForCurrentThread(cur->responsiblePID);
138 50 : GDALClose(cur->poDS);
139 : }
140 51 : CPLFree(cur);
141 51 : cur = next;
142 : }
143 44 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
144 44 : }
145 :
146 : /************************************************************************/
147 : /* ShowContent() */
148 : /************************************************************************/
149 :
150 0 : void GDALDatasetPool::ShowContent()
151 : {
152 0 : GDALProxyPoolCacheEntry* cur = firstEntry;
153 0 : int i = 0;
154 0 : while(cur)
155 : {
156 : printf("[%d] pszFileName=%s, refCount=%d, responsiblePID=%d\n",
157 0 : i, cur->pszFileName, cur->refCount, (int)cur->responsiblePID);
158 0 : i++;
159 0 : cur = cur->next;
160 : }
161 0 : }
162 :
163 : /************************************************************************/
164 : /* CheckLinks() */
165 : /************************************************************************/
166 :
167 0 : void GDALDatasetPool::CheckLinks()
168 : {
169 0 : GDALProxyPoolCacheEntry* cur = firstEntry;
170 0 : int i = 0;
171 0 : while(cur)
172 : {
173 : CPLAssert(cur == firstEntry || cur->prev->next == cur);
174 : CPLAssert(cur == lastEntry || cur->next->prev == cur);
175 0 : i++;
176 : CPLAssert(cur->next != NULL || cur == lastEntry);
177 0 : cur = cur->next;
178 : }
179 : CPLAssert(i == currentSize);
180 0 : }
181 :
182 : /************************************************************************/
183 : /* _RefDataset() */
184 : /************************************************************************/
185 :
186 4145 : GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName, GDALAccess eAccess)
187 : {
188 4145 : GDALProxyPoolCacheEntry* cur = firstEntry;
189 4145 : GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
190 4145 : GDALProxyPoolCacheEntry* lastEntryWithZeroRefCount = NULL;
191 :
192 8824 : while(cur)
193 : {
194 4628 : GDALProxyPoolCacheEntry* next = cur->next;
195 :
196 4628 : if (strcmp(cur->pszFileName, pszFileName) == 0 &&
197 : cur->responsiblePID == responsiblePID)
198 : {
199 4094 : if (cur != firstEntry)
200 : {
201 : /* Move to begin */
202 371 : if (cur->next)
203 144 : cur->next->prev = cur->prev;
204 : else
205 227 : lastEntry = cur->prev;
206 371 : cur->prev->next = cur->next;
207 371 : cur->prev = NULL;
208 371 : firstEntry->prev = cur;
209 371 : cur->next = firstEntry;
210 371 : firstEntry = cur;
211 :
212 : #ifdef DEBUG_PROXY_POOL
213 : CheckLinks();
214 : #endif
215 : }
216 :
217 4094 : cur->refCount ++;
218 4094 : return cur;
219 : }
220 :
221 534 : if (cur->refCount == 0)
222 451 : lastEntryWithZeroRefCount = cur;
223 :
224 534 : cur = next;
225 : }
226 :
227 51 : if (currentSize == maxSize)
228 : {
229 0 : if (lastEntryWithZeroRefCount == NULL)
230 : {
231 : CPLError(CE_Failure, CPLE_AppDefined,
232 : "Too many threads are running for the current value of the dataset pool size (%d).\n"
233 : "or too many proxy datasets are opened in a cascaded way.\n"
234 0 : "Try increasing GDAL_MAX_DATASET_POOL_SIZE.", maxSize);
235 0 : return NULL;
236 : }
237 :
238 0 : CPLFree(lastEntryWithZeroRefCount->pszFileName);
239 0 : lastEntryWithZeroRefCount->pszFileName = NULL;
240 0 : if (lastEntryWithZeroRefCount->poDS)
241 : {
242 : /* Close by pretending we are the thread that GDALOpen'ed this */
243 : /* dataset */
244 0 : GDALSetResponsiblePIDForCurrentThread(lastEntryWithZeroRefCount->responsiblePID);
245 :
246 0 : refCountOfDisableRefCount ++;
247 0 : GDALClose(lastEntryWithZeroRefCount->poDS);
248 0 : refCountOfDisableRefCount --;
249 :
250 0 : lastEntryWithZeroRefCount->poDS = NULL;
251 0 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
252 : }
253 :
254 : /* Recycle this entry for the to-be-openeded dataset and */
255 : /* moves it to the top of the list */
256 0 : if (lastEntryWithZeroRefCount->prev)
257 0 : lastEntryWithZeroRefCount->prev->next = lastEntryWithZeroRefCount->next;
258 : else
259 : CPLAssert(0);
260 0 : if (lastEntryWithZeroRefCount->next)
261 0 : lastEntryWithZeroRefCount->next->prev = lastEntryWithZeroRefCount->prev;
262 : else
263 : {
264 : CPLAssert(lastEntryWithZeroRefCount == lastEntry);
265 0 : lastEntry->prev->next = NULL;
266 0 : lastEntry = lastEntry->prev;
267 : }
268 0 : lastEntryWithZeroRefCount->prev = NULL;
269 0 : lastEntryWithZeroRefCount->next = firstEntry;
270 0 : firstEntry->prev = lastEntryWithZeroRefCount;
271 0 : cur = firstEntry = lastEntryWithZeroRefCount;
272 : #ifdef DEBUG_PROXY_POOL
273 : CheckLinks();
274 : #endif
275 : }
276 : else
277 : {
278 : /* Prepend */
279 51 : cur = (GDALProxyPoolCacheEntry*) CPLMalloc(sizeof(GDALProxyPoolCacheEntry));
280 51 : if (lastEntry == NULL)
281 25 : lastEntry = cur;
282 51 : cur->prev = NULL;
283 51 : cur->next = firstEntry;
284 51 : if (firstEntry)
285 26 : firstEntry->prev = cur;
286 51 : firstEntry = cur;
287 51 : currentSize ++;
288 : #ifdef DEBUG_PROXY_POOL
289 : CheckLinks();
290 : #endif
291 : }
292 :
293 51 : cur->pszFileName = CPLStrdup(pszFileName);
294 51 : cur->responsiblePID = responsiblePID;
295 51 : cur->refCount = 1;
296 :
297 51 : refCountOfDisableRefCount ++;
298 51 : cur->poDS = (GDALDataset*) GDALOpen(pszFileName, eAccess);
299 51 : refCountOfDisableRefCount --;
300 :
301 51 : return cur;
302 : }
303 :
304 : /************************************************************************/
305 : /* Ref() */
306 : /************************************************************************/
307 :
308 130 : void GDALDatasetPool::Ref()
309 : {
310 130 : CPLMutexHolderD( GDALGetphDLMutex() );
311 130 : if (singleton == NULL)
312 : {
313 44 : int maxSize = atoi(CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"));
314 44 : if (maxSize < 2 || maxSize > 1000)
315 0 : maxSize = 100;
316 44 : singleton = new GDALDatasetPool(maxSize);
317 : }
318 130 : if (singleton->refCountOfDisableRefCount == 0)
319 121 : singleton->refCount++;
320 130 : }
321 :
322 : /************************************************************************/
323 : /* Unref() */
324 : /************************************************************************/
325 :
326 130 : void GDALDatasetPool::Unref()
327 : {
328 130 : CPLMutexHolderD( GDALGetphDLMutex() );
329 130 : if (! singleton)
330 : {
331 : CPLAssert(0);
332 : return;
333 : }
334 130 : if (singleton->refCountOfDisableRefCount == 0)
335 : {
336 130 : singleton->refCount--;
337 130 : if (singleton->refCount == 0)
338 : {
339 44 : delete singleton;
340 44 : singleton = NULL;
341 : }
342 0 : }
343 : }
344 :
345 : /************************************************************************/
346 : /* RefDataset() */
347 : /************************************************************************/
348 :
349 4145 : GDALProxyPoolCacheEntry* GDALDatasetPool::RefDataset(const char* pszFileName, GDALAccess eAccess)
350 : {
351 4145 : CPLMutexHolderD( GDALGetphDLMutex() );
352 4145 : return singleton->_RefDataset(pszFileName, eAccess);
353 : }
354 :
355 : /************************************************************************/
356 : /* UnrefDataset() */
357 : /************************************************************************/
358 :
359 4145 : void GDALDatasetPool::UnrefDataset(GDALProxyPoolCacheEntry* cacheEntry)
360 : {
361 4145 : CPLMutexHolderD( GDALGetphDLMutex() );
362 4145 : cacheEntry->refCount --;
363 4145 : }
364 :
365 : CPL_C_START
366 :
367 : typedef struct
368 : {
369 : char* pszDomain;
370 : char** papszMetadata;
371 : } GetMetadataElt;
372 :
373 : static
374 0 : unsigned long hash_func_get_metadata(const void* _elt)
375 : {
376 0 : GetMetadataElt* elt = (GetMetadataElt*) _elt;
377 0 : return CPLHashSetHashStr(elt->pszDomain);
378 : }
379 :
380 : static
381 0 : int equal_func_get_metadata(const void* _elt1, const void* _elt2)
382 : {
383 0 : GetMetadataElt* elt1 = (GetMetadataElt*) _elt1;
384 0 : GetMetadataElt* elt2 = (GetMetadataElt*) _elt2;
385 0 : return CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
386 : }
387 :
388 : static
389 0 : void free_func_get_metadata(void* _elt)
390 : {
391 0 : GetMetadataElt* elt = (GetMetadataElt*) _elt;
392 0 : CPLFree(elt->pszDomain);
393 0 : CSLDestroy(elt->papszMetadata);
394 0 : }
395 :
396 :
397 : typedef struct
398 : {
399 : char* pszName;
400 : char* pszDomain;
401 : char* pszMetadataItem;
402 : } GetMetadataItemElt;
403 :
404 : static
405 0 : unsigned long hash_func_get_metadata_item(const void* _elt)
406 : {
407 0 : GetMetadataItemElt* elt = (GetMetadataItemElt*) _elt;
408 0 : return CPLHashSetHashStr(elt->pszName) ^ CPLHashSetHashStr(elt->pszDomain);
409 : }
410 :
411 : static
412 0 : int equal_func_get_metadata_item(const void* _elt1, const void* _elt2)
413 : {
414 0 : GetMetadataItemElt* elt1 = (GetMetadataItemElt*) _elt1;
415 0 : GetMetadataItemElt* elt2 = (GetMetadataItemElt*) _elt2;
416 : return CPLHashSetEqualStr(elt1->pszName, elt2->pszName) &&
417 0 : CPLHashSetEqualStr(elt1->pszDomain, elt2->pszDomain);
418 : }
419 :
420 : static
421 0 : void free_func_get_metadata_item(void* _elt)
422 : {
423 0 : GetMetadataItemElt* elt = (GetMetadataItemElt*) _elt;
424 0 : CPLFree(elt->pszName);
425 0 : CPLFree(elt->pszDomain);
426 0 : CPLFree(elt->pszMetadataItem);
427 0 : }
428 :
429 : CPL_C_END
430 :
431 : /* ******************************************************************** */
432 : /* GDALProxyPoolDataset */
433 : /* ******************************************************************** */
434 :
435 130 : GDALProxyPoolDataset::GDALProxyPoolDataset(const char* pszSourceDatasetDescription,
436 : int nRasterXSize, int nRasterYSize,
437 : GDALAccess eAccess, int bShared,
438 : const char * pszProjectionRef,
439 130 : double * padfGeoTransform)
440 : {
441 130 : GDALDatasetPool::Ref();
442 :
443 130 : SetDescription(pszSourceDatasetDescription);
444 :
445 130 : this->nRasterXSize = nRasterXSize;
446 130 : this->nRasterYSize = nRasterYSize;
447 130 : this->eAccess = eAccess;
448 :
449 130 : this->bShared = bShared;
450 :
451 130 : this->responsiblePID = GDALGetResponsiblePIDForCurrentThread();
452 :
453 130 : if (pszProjectionRef)
454 : {
455 46 : this->pszProjectionRef = NULL;
456 46 : bHasSrcProjection = FALSE;
457 : }
458 : else
459 : {
460 84 : this->pszProjectionRef = CPLStrdup(pszProjectionRef);
461 84 : bHasSrcProjection = TRUE;
462 : }
463 130 : if (padfGeoTransform)
464 : {
465 38 : memcpy(adfGeoTransform, padfGeoTransform,6 * sizeof(double));
466 38 : bHasSrcGeoTransform = TRUE;
467 : }
468 : else
469 : {
470 92 : adfGeoTransform[0] = 0;
471 92 : adfGeoTransform[1] = 1;
472 92 : adfGeoTransform[2] = 0;
473 92 : adfGeoTransform[3] = 0;
474 92 : adfGeoTransform[4] = 0;
475 92 : adfGeoTransform[5] = 1;
476 92 : bHasSrcGeoTransform = FALSE;
477 : }
478 :
479 130 : pszGCPProjection = NULL;
480 130 : nGCPCount = 0;
481 130 : pasGCPList = NULL;
482 130 : metadataSet = NULL;
483 130 : metadataItemSet = NULL;
484 130 : cacheEntry = NULL;
485 130 : }
486 :
487 : /************************************************************************/
488 : /* ~GDALProxyPoolDataset() */
489 : /************************************************************************/
490 :
491 252 : GDALProxyPoolDataset::~GDALProxyPoolDataset()
492 : {
493 130 : CPLFree(pszProjectionRef);
494 130 : CPLFree(pszGCPProjection);
495 130 : if (nGCPCount)
496 : {
497 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
498 0 : CPLFree( pasGCPList );
499 : }
500 130 : if (metadataSet)
501 0 : CPLHashSetDestroy(metadataSet);
502 130 : if (metadataItemSet)
503 0 : CPLHashSetDestroy(metadataItemSet);
504 :
505 130 : GDALDatasetPool::Unref();
506 252 : }
507 :
508 : /************************************************************************/
509 : /* AddSrcBandDescription() */
510 : /************************************************************************/
511 :
512 132 : void GDALProxyPoolDataset::AddSrcBandDescription( GDALDataType eDataType, int nBlockXSize, int nBlockYSize)
513 : {
514 132 : SetBand(nBands + 1, new GDALProxyPoolRasterBand(this, nBands + 1, eDataType, nBlockXSize, nBlockYSize));
515 132 : }
516 :
517 : /************************************************************************/
518 : /* RefUnderlyingDataset() */
519 : /************************************************************************/
520 :
521 4145 : GDALDataset* GDALProxyPoolDataset::RefUnderlyingDataset()
522 : {
523 : /* We pretend that the current thread is responsiblePID, that is */
524 : /* to say the thread that created that GDALProxyPoolDataset object. */
525 : /* This is for the case when a GDALProxyPoolDataset is created by a */
526 : /* thread and used by other threads. These other threads, when doing actual */
527 : /* IO, will come there and potentially open the underlying dataset. */
528 : /* By doing this, they can indirectly call GDALOpenShared() on .aux file */
529 : /* for example. So this call to GDALOpenShared() must occur as if it */
530 : /* was done by the creating thread, otherwise it will not be correctly closed afterwards... */
531 : /* To make a long story short : this is necessary when warping with ChunkAndWarpMulti */
532 : /* a VRT of GeoTIFFs that have associated .aux files */
533 4145 : GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
534 4145 : GDALSetResponsiblePIDForCurrentThread(responsiblePID);
535 4145 : cacheEntry = GDALDatasetPool::RefDataset(GetDescription(), eAccess);
536 4145 : GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
537 4145 : if (cacheEntry != NULL)
538 : {
539 4145 : if (cacheEntry->poDS != NULL)
540 4144 : return cacheEntry->poDS;
541 : else
542 1 : GDALDatasetPool::UnrefDataset(cacheEntry);
543 : }
544 1 : return NULL;
545 : }
546 :
547 : /************************************************************************/
548 : /* UnrefUnderlyingDataset() */
549 : /************************************************************************/
550 :
551 4144 : void GDALProxyPoolDataset::UnrefUnderlyingDataset(GDALDataset* poUnderlyingDataset)
552 : {
553 4144 : if (cacheEntry != NULL)
554 : {
555 : CPLAssert(cacheEntry->poDS == poUnderlyingDataset);
556 4144 : if (cacheEntry->poDS != NULL)
557 4144 : GDALDatasetPool::UnrefDataset(cacheEntry);
558 : }
559 4144 : }
560 :
561 : /************************************************************************/
562 : /* SetProjection() */
563 : /************************************************************************/
564 :
565 0 : CPLErr GDALProxyPoolDataset::SetProjection(const char* pszProjectionRef)
566 : {
567 0 : bHasSrcProjection = FALSE;
568 0 : return GDALProxyDataset::SetProjection(pszProjectionRef);
569 : }
570 :
571 : /************************************************************************/
572 : /* GetProjectionRef() */
573 : /************************************************************************/
574 :
575 4 : const char *GDALProxyPoolDataset::GetProjectionRef()
576 : {
577 4 : if (bHasSrcProjection)
578 0 : return pszProjectionRef;
579 : else
580 4 : return GDALProxyDataset::GetProjectionRef();
581 : }
582 :
583 : /************************************************************************/
584 : /* SetGeoTransform() */
585 : /************************************************************************/
586 :
587 0 : CPLErr GDALProxyPoolDataset::SetGeoTransform( double * padfGeoTransform )
588 : {
589 0 : bHasSrcGeoTransform = FALSE;
590 0 : return GDALProxyDataset::SetGeoTransform(padfGeoTransform);
591 : }
592 :
593 : /************************************************************************/
594 : /* GetGeoTransform() */
595 : /************************************************************************/
596 :
597 0 : CPLErr GDALProxyPoolDataset::GetGeoTransform( double * padfGeoTransform )
598 : {
599 0 : if (bHasSrcGeoTransform)
600 : {
601 0 : memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
602 0 : return CE_None;
603 : }
604 : else
605 : {
606 0 : return GDALProxyDataset::GetGeoTransform(padfGeoTransform);
607 : }
608 : }
609 :
610 : /************************************************************************/
611 : /* GetMetadata() */
612 : /************************************************************************/
613 :
614 0 : char **GDALProxyPoolDataset::GetMetadata( const char * pszDomain )
615 : {
616 0 : if (metadataSet == NULL)
617 : metadataSet = CPLHashSetNew(hash_func_get_metadata,
618 : equal_func_get_metadata,
619 0 : free_func_get_metadata);
620 :
621 0 : GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
622 0 : if (poUnderlyingDataset == NULL)
623 0 : return NULL;
624 :
625 0 : char** papszUnderlyingMetadata = poUnderlyingDataset->GetMetadata(pszDomain);
626 :
627 0 : GetMetadataElt* pElt = (GetMetadataElt*) CPLMalloc(sizeof(GetMetadataElt));
628 0 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
629 0 : pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
630 0 : CPLHashSetInsert(metadataSet, pElt);
631 :
632 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
633 :
634 0 : return pElt->papszMetadata;
635 : }
636 :
637 : /************************************************************************/
638 : /* GetMetadataItem() */
639 : /************************************************************************/
640 :
641 0 : const char *GDALProxyPoolDataset::GetMetadataItem( const char * pszName,
642 : const char * pszDomain )
643 : {
644 0 : if (metadataItemSet == NULL)
645 : metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
646 : equal_func_get_metadata_item,
647 0 : free_func_get_metadata_item);
648 :
649 0 : GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
650 0 : if (poUnderlyingDataset == NULL)
651 0 : return NULL;
652 :
653 : const char* pszUnderlyingMetadataItem =
654 0 : poUnderlyingDataset->GetMetadataItem(pszName, pszDomain);
655 :
656 0 : GetMetadataItemElt* pElt = (GetMetadataItemElt*) CPLMalloc(sizeof(GetMetadataItemElt));
657 0 : pElt->pszName = (pszName) ? CPLStrdup(pszName) : NULL;
658 0 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
659 0 : pElt->pszMetadataItem = (pszUnderlyingMetadataItem) ? CPLStrdup(pszUnderlyingMetadataItem) : NULL;
660 0 : CPLHashSetInsert(metadataItemSet, pElt);
661 :
662 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
663 :
664 0 : return pElt->pszMetadataItem;
665 : }
666 :
667 : /************************************************************************/
668 : /* GetInternalHandle() */
669 : /************************************************************************/
670 :
671 0 : void *GDALProxyPoolDataset::GetInternalHandle( const char * pszRequest)
672 : {
673 : CPLError(CE_Warning, CPLE_AppDefined,
674 : "GetInternalHandle() cannot be safely called on a proxy pool dataset\n"
675 0 : "as the returned value may be invalidated at any time.\n");
676 0 : return GDALProxyDataset::GetInternalHandle(pszRequest);
677 : }
678 :
679 : /************************************************************************/
680 : /* GetGCPProjection() */
681 : /************************************************************************/
682 :
683 0 : const char *GDALProxyPoolDataset::GetGCPProjection()
684 : {
685 0 : GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
686 0 : if (poUnderlyingDataset == NULL)
687 0 : return NULL;
688 :
689 0 : CPLFree(pszGCPProjection);
690 0 : pszGCPProjection = NULL;
691 :
692 0 : const char* pszUnderlyingGCPProjection = poUnderlyingDataset->GetGCPProjection();
693 0 : if (pszUnderlyingGCPProjection)
694 0 : pszGCPProjection = CPLStrdup(pszUnderlyingGCPProjection);
695 :
696 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
697 :
698 0 : return pszGCPProjection;
699 : }
700 :
701 : /************************************************************************/
702 : /* GetGCPs() */
703 : /************************************************************************/
704 :
705 0 : const GDAL_GCP *GDALProxyPoolDataset::GetGCPs()
706 : {
707 0 : GDALDataset* poUnderlyingDataset = RefUnderlyingDataset();
708 0 : if (poUnderlyingDataset == NULL)
709 0 : return NULL;
710 :
711 0 : if (nGCPCount)
712 : {
713 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
714 0 : CPLFree( pasGCPList );
715 0 : pasGCPList = NULL;
716 : }
717 :
718 0 : const GDAL_GCP* pasUnderlyingGCPList = poUnderlyingDataset->GetGCPs();
719 0 : nGCPCount = poUnderlyingDataset->GetGCPCount();
720 0 : if (nGCPCount)
721 0 : pasGCPList = GDALDuplicateGCPs(nGCPCount, pasUnderlyingGCPList );
722 :
723 0 : UnrefUnderlyingDataset(poUnderlyingDataset);
724 :
725 0 : return pasGCPList;
726 : }
727 :
728 : /************************************************************************/
729 : /* GDALProxyPoolDatasetCreate() */
730 : /************************************************************************/
731 :
732 38 : GDALProxyPoolDatasetH GDALProxyPoolDatasetCreate(const char* pszSourceDatasetDescription,
733 : int nRasterXSize, int nRasterYSize,
734 : GDALAccess eAccess, int bShared,
735 : const char * pszProjectionRef,
736 : double * padfGeoTransform)
737 : {
738 : return (GDALProxyPoolDatasetH)
739 : new GDALProxyPoolDataset(pszSourceDatasetDescription,
740 : nRasterXSize, nRasterYSize,
741 : eAccess, bShared,
742 38 : pszProjectionRef, padfGeoTransform);
743 : }
744 :
745 : /************************************************************************/
746 : /* GDALProxyPoolDatasetDelete() */
747 : /************************************************************************/
748 :
749 0 : void CPL_DLL GDALProxyPoolDatasetDelete(GDALProxyPoolDatasetH hProxyPoolDataset)
750 : {
751 0 : delete (GDALProxyPoolDataset*)hProxyPoolDataset;
752 0 : }
753 :
754 : /************************************************************************/
755 : /* GDALProxyPoolDatasetAddSrcBandDescription() */
756 : /************************************************************************/
757 :
758 42 : void GDALProxyPoolDatasetAddSrcBandDescription( GDALProxyPoolDatasetH hProxyPoolDataset,
759 : GDALDataType eDataType,
760 : int nBlockXSize, int nBlockYSize)
761 : {
762 : ((GDALProxyPoolDataset*)hProxyPoolDataset)->
763 42 : AddSrcBandDescription(eDataType, nBlockXSize, nBlockYSize);
764 42 : }
765 :
766 : /* ******************************************************************** */
767 : /* GDALProxyPoolRasterBand() */
768 : /* ******************************************************************** */
769 :
770 132 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset* poDS, int nBand,
771 : GDALDataType eDataType,
772 132 : int nBlockXSize, int nBlockYSize)
773 : {
774 132 : this->poDS = poDS;
775 132 : this->nBand = nBand;
776 132 : this->eDataType = eDataType;
777 132 : this->nRasterXSize = poDS->GetRasterXSize();
778 132 : this->nRasterYSize = poDS->GetRasterYSize();
779 132 : this->nBlockXSize = nBlockXSize;
780 132 : this->nBlockYSize = nBlockYSize;
781 :
782 132 : Init();
783 132 : }
784 :
785 : /* ******************************************************************** */
786 : /* GDALProxyPoolRasterBand() */
787 : /* ******************************************************************** */
788 :
789 0 : GDALProxyPoolRasterBand::GDALProxyPoolRasterBand(GDALProxyPoolDataset* poDS,
790 0 : GDALRasterBand* poUnderlyingRasterBand)
791 : {
792 0 : this->poDS = poDS;
793 0 : this->nBand = poUnderlyingRasterBand->GetBand();
794 0 : this->eDataType = poUnderlyingRasterBand->GetRasterDataType();
795 0 : this->nRasterXSize = poUnderlyingRasterBand->GetXSize();
796 0 : this->nRasterYSize = poUnderlyingRasterBand->GetYSize();
797 0 : poUnderlyingRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
798 :
799 0 : Init();
800 0 : }
801 :
802 : /* ******************************************************************** */
803 : /* Init() */
804 : /* ******************************************************************** */
805 :
806 132 : void GDALProxyPoolRasterBand::Init()
807 : {
808 132 : metadataSet = NULL;
809 132 : metadataItemSet = NULL;
810 132 : pszUnitType = NULL;
811 132 : papszCategoryNames = NULL;
812 132 : poColorTable = NULL;
813 :
814 132 : nSizeProxyOverviewRasterBand = 0;
815 132 : papoProxyOverviewRasterBand = NULL;
816 132 : poProxyMaskBand = NULL;
817 132 : }
818 :
819 : /* ******************************************************************** */
820 : /* ~GDALProxyPoolRasterBand() */
821 : /* ******************************************************************** */
822 264 : GDALProxyPoolRasterBand::~GDALProxyPoolRasterBand()
823 : {
824 132 : if (metadataSet)
825 0 : CPLHashSetDestroy(metadataSet);
826 132 : if (metadataItemSet)
827 0 : CPLHashSetDestroy(metadataItemSet);
828 132 : CPLFree(pszUnitType);
829 132 : CSLDestroy(papszCategoryNames);
830 132 : if (poColorTable)
831 7 : delete poColorTable;
832 :
833 : int i;
834 132 : for(i=0;i<nSizeProxyOverviewRasterBand;i++)
835 : {
836 0 : if (papoProxyOverviewRasterBand[i])
837 0 : delete papoProxyOverviewRasterBand[i];
838 : }
839 132 : CPLFree(papoProxyOverviewRasterBand);
840 132 : if (poProxyMaskBand)
841 0 : delete poProxyMaskBand;
842 264 : }
843 :
844 :
845 : /************************************************************************/
846 : /* RefUnderlyingRasterBand() */
847 : /************************************************************************/
848 :
849 3781 : GDALRasterBand* GDALProxyPoolRasterBand::RefUnderlyingRasterBand()
850 : {
851 3781 : GDALDataset* poUnderlyingDataset = ((GDALProxyPoolDataset*)poDS)->RefUnderlyingDataset();
852 3781 : if (poUnderlyingDataset == NULL)
853 1 : return NULL;
854 :
855 3780 : return poUnderlyingDataset->GetRasterBand(nBand);
856 : }
857 :
858 : /************************************************************************/
859 : /* UnrefUnderlyingRasterBand() */
860 : /************************************************************************/
861 :
862 3780 : void GDALProxyPoolRasterBand::UnrefUnderlyingRasterBand(GDALRasterBand* poUnderlyingRasterBand)
863 : {
864 3780 : if (poUnderlyingRasterBand)
865 3780 : ((GDALProxyPoolDataset*)poDS)->UnrefUnderlyingDataset(poUnderlyingRasterBand->GetDataset());
866 3780 : }
867 :
868 : /************************************************************************/
869 : /* GetMetadata() */
870 : /************************************************************************/
871 :
872 0 : char **GDALProxyPoolRasterBand::GetMetadata( const char * pszDomain )
873 : {
874 0 : if (metadataSet == NULL)
875 : metadataSet = CPLHashSetNew(hash_func_get_metadata,
876 : equal_func_get_metadata,
877 0 : free_func_get_metadata);
878 :
879 0 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
880 0 : if (poUnderlyingRasterBand == NULL)
881 0 : return NULL;
882 :
883 0 : char** papszUnderlyingMetadata = poUnderlyingRasterBand->GetMetadata(pszDomain);
884 :
885 0 : GetMetadataElt* pElt = (GetMetadataElt*) CPLMalloc(sizeof(GetMetadataElt));
886 0 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
887 0 : pElt->papszMetadata = CSLDuplicate(papszUnderlyingMetadata);
888 0 : CPLHashSetInsert(metadataSet, pElt);
889 :
890 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
891 :
892 0 : return pElt->papszMetadata;
893 : }
894 :
895 : /************************************************************************/
896 : /* GetMetadataItem() */
897 : /************************************************************************/
898 :
899 0 : const char *GDALProxyPoolRasterBand::GetMetadataItem( const char * pszName,
900 : const char * pszDomain )
901 : {
902 0 : if (metadataItemSet == NULL)
903 : metadataItemSet = CPLHashSetNew(hash_func_get_metadata_item,
904 : equal_func_get_metadata_item,
905 0 : free_func_get_metadata_item);
906 :
907 0 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
908 0 : if (poUnderlyingRasterBand == NULL)
909 0 : return NULL;
910 :
911 : const char* pszUnderlyingMetadataItem =
912 0 : poUnderlyingRasterBand->GetMetadataItem(pszName, pszDomain);
913 :
914 0 : GetMetadataItemElt* pElt = (GetMetadataItemElt*) CPLMalloc(sizeof(GetMetadataItemElt));
915 0 : pElt->pszName = (pszName) ? CPLStrdup(pszName) : NULL;
916 0 : pElt->pszDomain = (pszDomain) ? CPLStrdup(pszDomain) : NULL;
917 0 : pElt->pszMetadataItem = (pszUnderlyingMetadataItem) ? CPLStrdup(pszUnderlyingMetadataItem) : NULL;
918 0 : CPLHashSetInsert(metadataItemSet, pElt);
919 :
920 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
921 :
922 0 : return pElt->pszMetadataItem;
923 : }
924 :
925 : /* ******************************************************************** */
926 : /* GetCategoryNames() */
927 : /* ******************************************************************** */
928 :
929 0 : char **GDALProxyPoolRasterBand::GetCategoryNames()
930 : {
931 0 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
932 0 : if (poUnderlyingRasterBand == NULL)
933 0 : return NULL;
934 :
935 0 : CSLDestroy(papszCategoryNames);
936 0 : papszCategoryNames = NULL;
937 :
938 0 : char** papszUnderlyingCategoryNames = poUnderlyingRasterBand->GetCategoryNames();
939 0 : if (papszUnderlyingCategoryNames)
940 0 : papszCategoryNames = CSLDuplicate(papszUnderlyingCategoryNames);
941 :
942 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
943 :
944 0 : return papszCategoryNames;
945 : }
946 :
947 : /* ******************************************************************** */
948 : /* GetUnitType() */
949 : /* ******************************************************************** */
950 :
951 0 : const char *GDALProxyPoolRasterBand::GetUnitType()
952 : {
953 0 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
954 0 : if (poUnderlyingRasterBand == NULL)
955 0 : return NULL;
956 :
957 0 : CPLFree(pszUnitType);
958 0 : pszUnitType = NULL;
959 :
960 0 : const char* pszUnderlyingUnitType = poUnderlyingRasterBand->GetUnitType();
961 0 : if (pszUnderlyingUnitType)
962 0 : pszUnitType = CPLStrdup(pszUnderlyingUnitType);
963 :
964 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
965 :
966 0 : return pszUnitType;
967 : }
968 :
969 : /* ******************************************************************** */
970 : /* GetColorTable() */
971 : /* ******************************************************************** */
972 :
973 1603 : GDALColorTable *GDALProxyPoolRasterBand::GetColorTable()
974 : {
975 1603 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
976 1603 : if (poUnderlyingRasterBand == NULL)
977 0 : return NULL;
978 :
979 1603 : if (poColorTable)
980 1596 : delete poColorTable;
981 1603 : poColorTable = NULL;
982 :
983 1603 : GDALColorTable* poUnderlyingColorTable = poUnderlyingRasterBand->GetColorTable();
984 1603 : if (poUnderlyingColorTable)
985 1603 : poColorTable = poUnderlyingColorTable->Clone();
986 :
987 1603 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
988 :
989 1603 : return poColorTable;
990 : }
991 :
992 : /* ******************************************************************** */
993 : /* GetOverview() */
994 : /* ******************************************************************** */
995 :
996 0 : GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
997 : {
998 0 : if (nOverviewBand >= 0 && nOverviewBand < nSizeProxyOverviewRasterBand)
999 : {
1000 0 : if (papoProxyOverviewRasterBand[nOverviewBand])
1001 0 : return papoProxyOverviewRasterBand[nOverviewBand];
1002 : }
1003 :
1004 0 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1005 0 : if (poUnderlyingRasterBand == NULL)
1006 0 : return NULL;
1007 :
1008 0 : GDALRasterBand* poOverviewRasterBand = poUnderlyingRasterBand->GetOverview(nOverviewBand);
1009 0 : if (poOverviewRasterBand == NULL)
1010 : {
1011 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1012 0 : return NULL;
1013 : }
1014 :
1015 0 : if (nOverviewBand >= nSizeProxyOverviewRasterBand)
1016 : {
1017 : int i;
1018 : papoProxyOverviewRasterBand = (GDALProxyPoolOverviewRasterBand**)
1019 : CPLRealloc(papoProxyOverviewRasterBand,
1020 0 : sizeof(GDALProxyPoolOverviewRasterBand*) * (nOverviewBand + 1));
1021 0 : for(i=nSizeProxyOverviewRasterBand; i<nOverviewBand + 1;i++)
1022 0 : papoProxyOverviewRasterBand[i] = NULL;
1023 0 : nSizeProxyOverviewRasterBand = nOverviewBand + 1;
1024 : }
1025 :
1026 0 : papoProxyOverviewRasterBand[nOverviewBand] =
1027 : new GDALProxyPoolOverviewRasterBand((GDALProxyPoolDataset*)poDS,
1028 : poOverviewRasterBand,
1029 0 : this, nOverviewBand);
1030 :
1031 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1032 :
1033 0 : return papoProxyOverviewRasterBand[nOverviewBand];
1034 : }
1035 :
1036 : /* ******************************************************************** */
1037 : /* GetRasterSampleOverview() */
1038 : /* ******************************************************************** */
1039 :
1040 0 : GDALRasterBand *GDALProxyPoolRasterBand::GetRasterSampleOverview( int nDesiredSamples)
1041 : {
1042 : CPLError(CE_Failure, CPLE_AppDefined,
1043 0 : "GDALProxyPoolRasterBand::GetRasterSampleOverview : not implemented yet");
1044 0 : return NULL;
1045 : }
1046 :
1047 : /* ******************************************************************** */
1048 : /* GetMaskBand() */
1049 : /* ******************************************************************** */
1050 :
1051 0 : GDALRasterBand *GDALProxyPoolRasterBand::GetMaskBand()
1052 : {
1053 0 : if (poProxyMaskBand)
1054 0 : return poProxyMaskBand;
1055 :
1056 0 : GDALRasterBand* poUnderlyingRasterBand = RefUnderlyingRasterBand();
1057 0 : if (poUnderlyingRasterBand == NULL)
1058 0 : return NULL;
1059 :
1060 0 : GDALRasterBand* poMaskBand = poUnderlyingRasterBand->GetMaskBand();
1061 :
1062 : poProxyMaskBand =
1063 : new GDALProxyPoolMaskBand((GDALProxyPoolDataset*)poDS,
1064 : poMaskBand,
1065 0 : this);
1066 :
1067 0 : UnrefUnderlyingRasterBand(poUnderlyingRasterBand);
1068 :
1069 0 : return poProxyMaskBand;
1070 : }
1071 :
1072 : /* ******************************************************************** */
1073 : /* GDALProxyPoolOverviewRasterBand() */
1074 : /* ******************************************************************** */
1075 :
1076 0 : GDALProxyPoolOverviewRasterBand::GDALProxyPoolOverviewRasterBand(GDALProxyPoolDataset* poDS,
1077 : GDALRasterBand* poUnderlyingOverviewBand,
1078 : GDALProxyPoolRasterBand* poMainBand,
1079 : int nOverviewBand) :
1080 0 : GDALProxyPoolRasterBand(poDS, poUnderlyingOverviewBand)
1081 : {
1082 0 : this->poMainBand = poMainBand;
1083 0 : this->nOverviewBand = nOverviewBand;
1084 :
1085 0 : poUnderlyingMainRasterBand = NULL;
1086 0 : nRefCountUnderlyingMainRasterBand = 0;
1087 0 : }
1088 :
1089 : /* ******************************************************************** */
1090 : /* ~GDALProxyPoolOverviewRasterBand() */
1091 : /* ******************************************************************** */
1092 :
1093 0 : GDALProxyPoolOverviewRasterBand::~GDALProxyPoolOverviewRasterBand()
1094 : {
1095 : CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1096 0 : }
1097 :
1098 : /* ******************************************************************** */
1099 : /* RefUnderlyingRasterBand() */
1100 : /* ******************************************************************** */
1101 :
1102 0 : GDALRasterBand* GDALProxyPoolOverviewRasterBand::RefUnderlyingRasterBand()
1103 : {
1104 0 : poUnderlyingMainRasterBand = poMainBand->RefUnderlyingRasterBand();
1105 0 : if (poUnderlyingMainRasterBand == NULL)
1106 0 : return NULL;
1107 :
1108 0 : nRefCountUnderlyingMainRasterBand ++;
1109 0 : return poUnderlyingMainRasterBand->GetOverview(nOverviewBand);
1110 : }
1111 :
1112 : /* ******************************************************************** */
1113 : /* UnrefUnderlyingRasterBand() */
1114 : /* ******************************************************************** */
1115 :
1116 0 : void GDALProxyPoolOverviewRasterBand::UnrefUnderlyingRasterBand(GDALRasterBand* poUnderlyingRasterBand)
1117 : {
1118 0 : poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1119 0 : nRefCountUnderlyingMainRasterBand --;
1120 0 : }
1121 :
1122 :
1123 : /* ******************************************************************** */
1124 : /* GDALProxyPoolMaskBand() */
1125 : /* ******************************************************************** */
1126 :
1127 0 : GDALProxyPoolMaskBand::GDALProxyPoolMaskBand(GDALProxyPoolDataset* poDS,
1128 : GDALRasterBand* poUnderlyingMaskBand,
1129 : GDALProxyPoolRasterBand* poMainBand) :
1130 0 : GDALProxyPoolRasterBand(poDS, poUnderlyingMaskBand)
1131 : {
1132 0 : this->poMainBand = poMainBand;
1133 :
1134 0 : poUnderlyingMainRasterBand = NULL;
1135 0 : nRefCountUnderlyingMainRasterBand = 0;
1136 0 : }
1137 :
1138 : /* ******************************************************************** */
1139 : /* ~GDALProxyPoolMaskBand() */
1140 : /* ******************************************************************** */
1141 :
1142 0 : GDALProxyPoolMaskBand::~GDALProxyPoolMaskBand()
1143 : {
1144 : CPLAssert(nRefCountUnderlyingMainRasterBand == 0);
1145 0 : }
1146 :
1147 : /* ******************************************************************** */
1148 : /* RefUnderlyingRasterBand() */
1149 : /* ******************************************************************** */
1150 :
1151 0 : GDALRasterBand* GDALProxyPoolMaskBand::RefUnderlyingRasterBand()
1152 : {
1153 0 : poUnderlyingMainRasterBand = poMainBand->RefUnderlyingRasterBand();
1154 0 : if (poUnderlyingMainRasterBand == NULL)
1155 0 : return NULL;
1156 :
1157 0 : nRefCountUnderlyingMainRasterBand ++;
1158 0 : return poUnderlyingMainRasterBand->GetMaskBand();
1159 : }
1160 :
1161 : /* ******************************************************************** */
1162 : /* UnrefUnderlyingRasterBand() */
1163 : /* ******************************************************************** */
1164 :
1165 0 : void GDALProxyPoolMaskBand::UnrefUnderlyingRasterBand(GDALRasterBand* poUnderlyingRasterBand)
1166 : {
1167 0 : poMainBand->UnrefUnderlyingRasterBand(poUnderlyingMainRasterBand);
1168 0 : nRefCountUnderlyingMainRasterBand --;
1169 0 : }
|