PageRenderTime 30ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/gdal-1.9.1-fedora/gcore/gdalproxypool.cpp

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