root/tags/gdal_1_3_2/gcore/gdalrasterband.cpp

Revision 9522, 106.0 kB (checked in by fwarmerdam, 3 years ago)

Removed/corrected references to GetBlockRef?().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  GDAL Core
5  * Purpose:  Base class for format specific band class implementation.  This
6  *           base class provides default implementation for many methods.
7  * Author:   Frank Warmerdam, warmerdam@pobox.com
8  *
9  ******************************************************************************
10  * Copyright (c) 1998, Frank Warmerdam
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  * $Log$
32  * Revision 1.77  2006/04/06 02:03:46  fwarmerdam
33  * Removed/corrected references to GetBlockRef().
34  *
35  * Revision 1.76  2006/03/28 14:49:56  fwarmerdam
36  * updated contact info
37  *
38  * Revision 1.75  2006/02/07 19:07:07  fwarmerdam
39  * applied some strategic improved outofmemory checking
40  *
41  * Revision 1.74  2005/11/01 22:17:17  fwarmerdam
42  * fixed GDALSetDefaultRAT (bug 985)
43  *
44  * Revision 1.73  2005/09/28 00:54:05  fwarmerdam
45  * Added some RAT docs.
46  *
47  * Revision 1.72  2005/09/24 19:02:46  fwarmerdam
48  * RAT functions honour GMO_IGNORE_UNIMPLEMENTED
49  *
50  * Revision 1.71  2005/09/23 20:53:09  fwarmerdam
51  * avoid issuing NotSupported errors if GMO_IGNORE_UNIMPLEMENTED is set
52  *
53  * Revision 1.70  2005/09/23 16:56:16  fwarmerdam
54  * Added default RAT methods
55  *
56  * Revision 1.69  2005/07/25 23:15:10  fwarmerdam
57  * Fixed another doc typo.
58  *
59  * Revision 1.68  2005/07/25 23:14:27  fwarmerdam
60  * Fixed typo in BuildOverviews() docs.
61  *
62  * Revision 1.67  2005/07/11 21:07:33  fwarmerdam
63  * fixed a couple papoBlocks related multi-threading issues
64  *
65  * Revision 1.66  2005/05/23 06:42:57  fwarmerdam
66  * Updated for locking of block refs
67  *
68  * Revision 1.65  2005/05/19 14:45:16  fwarmerdam
69  * SetStatistics should now succeed.
70  *
71  * Revision 1.64  2005/05/16 21:35:16  fwarmerdam
72  * added CPLSetDefaultHistogram
73  *
74  * Revision 1.63  2005/05/13 18:19:37  fwarmerdam
75  * added SetDefaultHistogram
76  *
77  * Revision 1.62  2005/05/11 14:17:57  fwarmerdam
78  * include stdcall modifier for GDALGetDefaultHistogram
79  *
80  * Revision 1.61  2005/05/11 14:04:08  fwarmerdam
81  * added getdefaulthistogram
82  *
83  * Revision 1.60  2005/05/10 04:49:54  fwarmerdam
84  * added GetDefaultHistogram
85  *
86  * Revision 1.59  2005/05/03 21:09:54  fwarmerdam
87  * Removed unused variable.
88  *
89  * Revision 1.58  2005/04/27 16:30:28  fwarmerdam
90  * added statistics related methods
91  *
92  * Revision 1.57  2005/04/04 15:24:48  fwarmerdam
93  * Most C entry points now CPL_STDCALL
94  *
95  * Revision 1.56  2005/03/19 21:50:09  fwarmerdam
96  * bug 802: GetBlockRef()-adopt block before reading data into it
97  *
98  * Revision 1.55  2005/02/17 22:16:12  fwarmerdam
99  * changed to use two level block cache
100  *
101  * Revision 1.54  2005/01/15 16:10:43  fwarmerdam
102  * Added set scale/offset methods
103  *
104  * Revision 1.53  2005/01/04 21:14:01  fwarmerdam
105  * added GDAL_FORCE_CACHING config variable
106  */
107
108 #include "gdal_priv.h"
109 #include "gdal_rat.h"
110 #include "cpl_string.h"
111
112 #define SUBBLOCK_SIZE 64
113 #define TO_SUBBLOCK(x) ((x) >> 6)
114 #define WITHIN_SUBBLOCK(x) ((x) & 0x3f)
115
116 CPL_CVSID("$Id$");
117
118 /************************************************************************/
119 /*                           GDALRasterBand()                           */
120 /************************************************************************/
121
122 /*! Constructor. Applications should never create GDALRasterBands directly. */
123
124 GDALRasterBand::GDALRasterBand()
125
126 {
127     poDS = NULL;
128     nBand = 0;
129
130     eAccess = GA_ReadOnly;
131     nBlockXSize = nBlockYSize = -1;
132     eDataType = GDT_Byte;
133
134     nSubBlocksPerRow = nBlocksPerRow = 0;
135     nSubBlocksPerColumn = nBlocksPerColumn = 0;
136
137     bSubBlockingActive = FALSE;
138     papoBlocks = NULL;
139
140     nBlockReads = 0;
141     bForceCachedIO =  CSLTestBoolean(
142         CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") );
143 }
144
145 /************************************************************************/
146 /*                          ~GDALRasterBand()                           */
147 /************************************************************************/
148
149 /*! Destructor. Applications should never destroy GDALRasterBands directly,
150     instead destroy the GDALDataset. */
151
152 GDALRasterBand::~GDALRasterBand()
153
154 {
155     FlushCache();
156
157     CPLFree( papoBlocks );
158
159     if( nBlockReads > nBlocksPerRow * nBlocksPerColumn
160         && nBand == 1 && poDS != NULL )
161     {
162         CPLDebug( "GDAL", "%d block reads on %d block band 1 of %s.",
163                   nBlockReads, nBlocksPerRow * nBlocksPerColumn,
164                   poDS->GetDescription() );
165     }
166 }
167
168 /************************************************************************/
169 /*                              RasterIO()                              */
170 /************************************************************************/
171
172 /**
173  * Read/write a region of image data for this band.
174  *
175  * This method allows reading a region of a GDALRasterBand into a buffer,
176  * or writing data from a buffer into a region of a GDALRasterBand.  It
177  * automatically takes care of data type translation if the data type
178  * (eBufType) of the buffer is different than that of the GDALRasterBand.
179  * The method also takes care of image decimation / replication if the
180  * buffer size (nBufXSize x nBufYSize) is different than the size of the
181  * region being accessed (nXSize x nYSize).
182  *
183  * The nPixelSpace and nLineSpace parameters allow reading into or
184  * writing from unusually organized buffers.  This is primarily used
185  * for buffers containing more than one bands raster data in interleaved
186  * format.
187  *
188  * Some formats may efficiently implement decimation into a buffer by
189  * reading from lower resolution overview images.
190  *
191  * For highest performance full resolution data access, read and write
192  * on "block boundaries" as returned by GetBlockSize(), or use the
193  * ReadBlock() and WriteBlock() methods.
194  *
195  * This method is the same as the C GDALRasterIO() function.
196  *
197  * @param eRWFlag Either GF_Read to read a region of data, or GT_Write to
198  * write a region of data.
199  *
200  * @param nXOff The pixel offset to the top left corner of the region
201  * of the band to be accessed.  This would be zero to start from the left side.
202  *
203  * @param nYOff The line offset to the top left corner of the region
204  * of the band to be accessed.  This would be zero to start from the top.
205  *
206  * @param nXSize The width of the region of the band to be accessed in pixels.
207  *
208  * @param nYSize The height of the region of the band to be accessed in lines.
209  *
210  * @param pData The buffer into which the data should be read, or from which
211  * it should be written.  This buffer must contain at least nBufXSize *
212  * nBufYSize words of type eBufType.  It is organized in left to right,
213  * top to bottom pixel order.  Spacing is controlled by the nPixelSpace,
214  * and nLineSpace parameters.
215  *
216  * @param nBufXSize the width of the buffer image into which the desired region is
217  * to be read, or from which it is to be written.
218  *
219  * @param nBufYSize the height of the buffer image into which the desired region is
220  * to be read, or from which it is to be written.
221  *
222  * @param eBufType the type of the pixel values in the pData data buffer.  The
223  * pixel values will automatically be translated to/from the GDALRasterBand
224  * data type as needed.
225  *
226  * @param nPixelSpace The byte offset from the start of one pixel value in
227  * pData to the start of the next pixel value within a scanline.  If defaulted
228  * (0) the size of the datatype eBufType is used.
229  *
230  * @param nLineSpace The byte offset from the start of one scanline in
231  * pData to the start of the next.  If defaulted the size of the datatype
232  * eBufType * nBufXSize is used.
233  *
234  * @return CE_Failure if the access fails, otherwise CE_None.
235  */
236
237 CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
238                                  int nXOff, int nYOff, int nXSize, int nYSize,
239                                  void * pData, int nBufXSize, int nBufYSize,
240                                  GDALDataType eBufType,
241                                  int nPixelSpace,
242                                  int nLineSpace )
243
244 {
245 /* -------------------------------------------------------------------- */
246 /*      If pixel and line spaceing are defaulted assign reasonable      */
247 /*      value assuming a packed buffer.                                 */
248 /* -------------------------------------------------------------------- */
249     if( nPixelSpace == 0 )
250         nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
251    
252     if( nLineSpace == 0 )
253         nLineSpace = nPixelSpace * nBufXSize;
254    
255 /* -------------------------------------------------------------------- */
256 /*      Do some validation of parameters.                               */
257 /* -------------------------------------------------------------------- */
258     if( nXOff < 0 || nXOff + nXSize > nRasterXSize
259         || nYOff < 0 || nYOff + nYSize > nRasterYSize )
260     {
261         CPLError( CE_Failure, CPLE_IllegalArg,
262                   "Access window out of range in RasterIO().  Requested\n"
263                   "(%d,%d) of size %dx%d on raster of %dx%d.",
264                   nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize );
265         return CE_Failure;
266     }
267
268     if( eRWFlag != GF_Read && eRWFlag != GF_Write )
269     {
270         CPLError( CE_Failure, CPLE_IllegalArg,
271                   "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
272                   eRWFlag );
273         return CE_Failure;
274     }
275
276 /* -------------------------------------------------------------------- */
277 /*      Some size values are "noop".  Lets just return to avoid         */
278 /*      stressing lower level functions.                                */
279 /* -------------------------------------------------------------------- */
280     if( nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1 )
281     {
282         CPLDebug( "GDAL",
283                   "RasterIO() skipped for odd window or buffer size.\n"
284                   "  Window = (%d,%d)x%dx%d\n"
285                   "  Buffer = %dx%d\n",
286                   nXOff, nYOff, nXSize, nYSize,
287                   nBufXSize, nBufYSize );
288
289         return CE_None;
290     }
291    
292 /* -------------------------------------------------------------------- */
293 /*      Call the format specific function.                              */
294 /* -------------------------------------------------------------------- */
295     if( bForceCachedIO )
296         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
297                                          pData, nBufXSize, nBufYSize, eBufType,
298                                          nPixelSpace, nLineSpace );
299     else
300         return IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
301                           pData, nBufXSize, nBufYSize, eBufType,
302                           nPixelSpace, nLineSpace ) ;
303 }
304
305 /************************************************************************/
306 /*                            GDALRasterIO()                            */
307 /************************************************************************/
308
309 /**
310  * @see GDALRasterBand::Rasterio()
311  */
312
313 CPLErr CPL_STDCALL
314 GDALRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
315               int nXOff, int nYOff, int nXSize, int nYSize,
316               void * pData, int nBufXSize, int nBufYSize,
317               GDALDataType eBufType,
318               int nPixelSpace, int nLineSpace )
319    
320 {
321     GDALRasterBand      *poBand = (GDALRasterBand *) hBand;
322
323     return( poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
324                               pData, nBufXSize, nBufYSize, eBufType,
325                               nPixelSpace, nLineSpace ) );
326 }
327                      
328 /************************************************************************/
329 /*                             ReadBlock()                              */
330 /************************************************************************/
331
332 /**
333  * Read a block of image data efficiently.
334  *
335  * This method accesses a "natural" block from the raster band without
336  * resampling, or data type conversion.  For a more generalized, but
337  * potentially less efficient access use RasterIO().
338  *
339  * This method is the same as the C GDALReadBlock() function.
340  *
341  * See the GetLockedBlockRef() method for a way of accessing internally cached
342  * block oriented data without an extra copy into an application buffer.
343  *
344  * @param nXBlockOff the horizontal block offset, with zero indicating
345  * the left most block, 1 the next block and so forth.
346  *
347  * @param nYBlockOff the vertical block offset, with zero indicating
348  * the left most block, 1 the next block and so forth.
349  *
350  * @param pImage the buffer into which the data will be read.  The buffer
351  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
352  * of type GetRasterDataType().
353  *
354  * @return CE_None on success or CE_Failure on an error.
355  *
356  * The following code would efficiently compute a histogram of eight bit
357  * raster data.  Note that the final block may be partial ... data beyond
358  * the edge of the underlying raster band in these edge blocks is of an
359  * undermined value.
360  *
361 <pre>
362  CPLErr GetHistogram( GDALRasterBand *poBand, int *panHistogram )
363
364  {
365      int        nXBlocks, nYBlocks, nXBlockSize, nYBlockSize;
366      int        iXBlock, iYBlock;
367      GByte      *pabyData;
368
369      memset( panHistogram, 0, sizeof(int) * 256 );
370
371      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
372
373      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
374      nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
375      nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
376
377      pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
378
379      for( iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
380      {
381          for( iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
382          {
383              int        nXValid, nYValid;
384             
385              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
386
387              // Compute the portion of the block that is valid
388              // for partial edge blocks.
389              if( (iXBlock+1) * nXBlockSize > poBand->GetXSize() )
390                  nXValid = poBand->GetXSize() - iXBlock * nXBlockSize;
391              else
392                  nXValid = nXBlockSize;
393
394              if( (iYBlock+1) * nYBlockSize > poBand->GetYSize() )
395                  nYValid = poBand->GetYSize() - iYBlock * nYBlockSize;
396              else
397                  nYValid = nYBlockSize;
398
399              // Collect the histogram counts.
400              for( int iY = 0; iY < nYValid; iY++ )
401              {
402                  for( int iX = 0; iX < nXValid; iX++ )
403                  {
404                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
405                  }
406              }
407          }
408      }
409  }
410  
411 </pre>
412  */
413
414
415 CPLErr GDALRasterBand::ReadBlock( int nXBlockOff, int nYBlockOff,
416                                    void * pImage )
417
418 {
419 /* -------------------------------------------------------------------- */
420 /*      Validate arguments.                                             */
421 /* -------------------------------------------------------------------- */
422     CPLAssert( pImage != NULL );
423    
424     if( nXBlockOff < 0
425         || nXBlockOff*nBlockXSize >= nRasterXSize )
426     {
427         CPLError( CE_Failure, CPLE_IllegalArg,
428                   "Illegal nXBlockOff value (%d) in "
429                         "GDALRasterBand::ReadBlock()\n",
430                   nXBlockOff );
431
432         return( CE_Failure );
433     }
434
435     if( nYBlockOff < 0
436         || nYBlockOff*nBlockYSize >= nRasterYSize )
437     {
438         CPLError( CE_Failure, CPLE_IllegalArg,
439                   "Illegal nYBlockOff value (%d) in "
440                         "GDALRasterBand::ReadBlock()\n",
441                   nYBlockOff );
442
443         return( CE_Failure );
444     }
445    
446     if( !InitBlockInfo() )
447         return CE_Failure;
448
449 /* -------------------------------------------------------------------- */
450 /*      Invoke underlying implementation method.                        */
451 /* -------------------------------------------------------------------- */
452     return( IReadBlock( nXBlockOff, nYBlockOff, pImage ) );
453 }
454
455 /************************************************************************/
456 /*                           GDALReadBlock()                            */
457 /************************************************************************/
458
459 /**
460  * @see GDALRasterBand::ReadBlock()
461  */
462
463 CPLErr CPL_STDCALL GDALReadBlock( GDALRasterBandH hBand, int nXOff, int nYOff,
464                       void * pData )
465
466 {
467     GDALRasterBand      *poBand = (GDALRasterBand *) hBand;
468
469     return( poBand->ReadBlock( nXOff, nYOff, pData ) );
470 }
471
472 /************************************************************************/
473 /*                            IWriteBlock()                             */
474 /*                                                                      */
475 /*      Default internal implementation ... to be overriden by          */
476 /*      subclasses that support writing.                                */
477 /************************************************************************/
478
479 CPLErr GDALRasterBand::IWriteBlock( int, int, void * )
480
481 {
482     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
483         CPLError( CE_Failure, CPLE_NotSupported,
484                   "WriteBlock() not supported for this dataset." );
485    
486     return( CE_Failure );
487 }
488
489 /************************************************************************/
490 /*                             WriteBlock()                             */
491 /************************************************************************/
492
493 /**
494  * Write a block of image data efficiently.
495  *
496  * This method accesses a "natural" block from the raster band without
497  * resampling, or data type conversion.  For a more generalized, but
498  * potentially less efficient access use RasterIO().
499  *
500  * This method is the same as the C GDALWriteBlock() function.
501  *
502  * See ReadBlock() for an example of block oriented data access.
503  *
504  * @param nXBlockOff the horizontal block offset, with zero indicating
505  * the left most block, 1 the next block and so forth.
506  *
507  * @param nYBlockOff the vertical block offset, with zero indicating
508  * the left most block, 1 the next block and so forth.
509  *
510  * @param pImage the buffer from which the data will be written.  The buffer
511  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
512  * of type GetRasterDataType().
513  *
514  * @return CE_None on success or CE_Failure on an error.
515  *
516  * The following code would efficiently compute a histogram of eight bit
517  * raster data.  Note that the final block may be partial ... data beyond
518  * the edge of the underlying raster band in these edge blocks is of an
519  * undermined value.
520  *
521  */
522
523 CPLErr GDALRasterBand::WriteBlock( int nXBlockOff, int nYBlockOff,
524                                    void * pImage )
525
526 {
527 /* -------------------------------------------------------------------- */
528 /*      Validate arguments.                                             */
529 /* -------------------------------------------------------------------- */
530     CPLAssert( pImage != NULL );
531    
532     if( nXBlockOff < 0
533         || nXBlockOff*nBlockXSize >= GetXSize() )
534     {
535         CPLError( CE_Failure, CPLE_IllegalArg,
536                   "Illegal nXBlockOff value (%d) in "
537                         "GDALRasterBand::WriteBlock()\n",
538                   nXBlockOff );
539
540         return( CE_Failure );
541     }
542
543     if( nYBlockOff < 0
544         || nYBlockOff*nBlockYSize >= GetYSize() )
545     {
546         CPLError( CE_Failure, CPLE_IllegalArg,
547                   "Illegal nYBlockOff value (%d) in "
548                         "GDALRasterBand::WriteBlock()\n",
549                   nYBlockOff );
550
551         return( CE_Failure );
552     }
553
554     if( eAccess == GA_ReadOnly )
555     {
556         CPLError( CE_Failure, CPLE_NoWriteAccess,
557                   "Attempt to write to read only dataset in"
558                   "GDALRasterBand::WriteBlock().\n" );
559
560         return( CE_Failure );
561     }
562
563     if( !InitBlockInfo() )
564         return CE_Failure;
565    
566 /* -------------------------------------------------------------------- */
567 /*      Invoke underlying implementation method.                        */
568 /* -------------------------------------------------------------------- */
569     return( IWriteBlock( nXBlockOff, nYBlockOff, pImage ) );
570 }
571
572 /************************************************************************/
573 /*                           GDALWriteBlock()                           */
574 /************************************************************************/
575
576 /**
577  * @see GDALRasterBand::WriteBlock()
578  */
579
580 CPLErr CPL_STDCALL GDALWriteBlock( GDALRasterBandH hBand, int nXOff, int nYOff,
581                        void * pData )
582
583 {
584     GDALRasterBand      *poBand = (GDALRasterBand *) hBand;
585
586     return( poBand->WriteBlock( nXOff, nYOff, pData ) );
587 }
588
589
590 /************************************************************************/
591 /*                         GetRasterDataType()                          */
592 /************************************************************************/
593
594 /**
595  * Fetch the pixel data type for this band.
596  *
597  * @return the data type of pixels for this band.
598  */
599  
600
601 GDALDataType GDALRasterBand::GetRasterDataType()
602
603 {
604     return eDataType;
605 }
606
607 /************************************************************************/
608 /*                       GDALGetRasterDataType()                        */
609 /************************************************************************/
610
611 /**
612  * @see GDALRasterBand::GetRasterDataType()
613  */
614
615 GDALDataType CPL_STDCALL GDALGetRasterDataType( GDALRasterBandH hBand )
616
617 {
618     return( ((GDALRasterBand *) hBand)->GetRasterDataType() );
619 }
620
621 /************************************************************************/
622 /*                            GetBlockSize()                            */
623 /************************************************************************/
624
625 /**
626  * Fetch the "natural" block size of this band.
627  *
628  * GDAL contains a concept of the natural block size of rasters so that
629  * applications can organized data access efficiently for some file formats.
630  * The natural block size is the block size that is most efficient for
631  * accessing the format.  For many formats this is simple a whole scanline
632  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
633  *
634  * However, for tiled images this will typically be the tile size.
635  *
636  * Note that the X and Y block sizes don't have to divide the image size
637  * evenly, meaning that right and bottom edge blocks may be incomplete.
638  * See ReadBlock() for an example of code dealing with these issues.
639  *
640  * @param pnXSize integer to put the X block size into or NULL.
641  *
642  * @param pnYSize integer to put the Y block size into or NULL.
643  */
644
645 void GDALRasterBand::GetBlockSize( int * pnXSize, int *pnYSize )
646
647 {
648     CPLAssert( nBlockXSize > 0 && nBlockYSize > 0 );
649    
650     if( pnXSize != NULL )
651         *pnXSize = nBlockXSize;
652     if( pnYSize != NULL )
653         *pnYSize = nBlockYSize;
654 }
655
656 /************************************************************************/
657 /*                          GDALGetBlockSize()                          */
658 /************************************************************************/
659
660 /**
661  * @see GDALRasterBand::GetBlockSize()
662  */
663
664 void CPL_STDCALL
665 GDALGetBlockSize( GDALRasterBandH hBand, int * pnXSize, int * pnYSize )
666
667 {
668     GDALRasterBand      *poBand = (GDALRasterBand *) hBand;
669
670     poBand->GetBlockSize( pnXSize, pnYSize );
671 }
672
673 /************************************************************************/
674 /*                           InitBlockInfo()                            */
675 /************************************************************************/
676
677 int GDALRasterBand::InitBlockInfo()
678
679 {
680     if( papoBlocks != NULL )
681         return TRUE;
682
683     CPLAssert( nBlockXSize > 0 && nBlockYSize > 0 );
684
685     nBlocksPerRow = (nRasterXSize+nBlockXSize-1) / nBlockXSize;
686     nBlocksPerColumn = (nRasterYSize+nBlockYSize-1) / nBlockYSize;
687    
688     if( nBlocksPerRow < SUBBLOCK_SIZE/2 )
689     {
690         bSubBlockingActive = FALSE;
691        
692         papoBlocks = (GDALRasterBlock **)
693             VSICalloc( sizeof(void*), nBlocksPerRow * nBlocksPerColumn );
694     }
695     else
696     {
697         bSubBlockingActive = TRUE;
698
699         nSubBlocksPerRow = (nBlocksPerRow + SUBBLOCK_SIZE + 1)/SUBBLOCK_SIZE;
700         nSubBlocksPerColumn = (nBlocksPerColumn + SUBBLOCK_SIZE + 1)/SUBBLOCK_SIZE;
701        
702         papoBlocks = (GDALRasterBlock **)
703             VSICalloc( sizeof(void*), nSubBlocksPerRow * nSubBlocksPerColumn );
704     }
705
706     if( papoBlocks == NULL )
707     {
708         CPLError( CE_Failure, CPLE_OutOfMemory,
709                   "Out of memory in InitBlockInfo()." );
710         return FALSE;
711     }
712
713     return TRUE;
714 }
715
716 /************************************************************************/
717 /*                             AdoptBlock()                             */
718 /*                                                                      */
719 /*      Add a block to the raster band's block matrix.  If this         */
720 /*      exceeds our maximum blocks for this layer, flush the oldest     */
721 /*      block out.                                                      */
722 /*                                                                      */
723 /*      This method is protected.                                       */
724 /************************************************************************/
725
726 CPLErr GDALRasterBand::AdoptBlock( int nXBlockOff, int nYBlockOff,
727                                    GDALRasterBlock * poBlock )
728
729 {
730     int         nBlockIndex;
731    
732     InitBlockInfo();
733    
734 /* -------------------------------------------------------------------- */
735 /*      Simple case without subblocking.                                */
736 /* -------------------------------------------------------------------- */
737     if( !bSubBlockingActive )
738     {
739         nBlockIndex = nXBlockOff + nYBlockOff * nBlocksPerRow;
740
741         if( papoBlocks[nBlockIndex] == poBlock )
742             return( CE_None );
743
744         if( papoBlocks[nBlockIndex] != NULL )
745             FlushBlock( nXBlockOff, nYBlockOff );
746
747         papoBlocks[nBlockIndex] = poBlock;
748         poBlock->Touch();
749
750         return( CE_None );
751     }
752
753 /* -------------------------------------------------------------------- */
754 /*      Identify the subblock in which our target occurs, and create    */
755 /*      it if necessary.                                                */
756 /* -------------------------------------------------------------------- */
757     int nSubBlock = TO_SUBBLOCK(nXBlockOff)
758         + TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
759
760     if( papoBlocks[nSubBlock] == NULL )
761     {
762         int nSubGridSize =
763             sizeof(GDALRasterBlock*) * SUBBLOCK_SIZE * SUBBLOCK_SIZE;
764
765         papoBlocks[nSubBlock] = (GDALRasterBlock *) VSIMalloc(nSubGridSize);
766         if( papoBlocks[nSubBlock] == NULL )
767         {
768             CPLError( CE_Failure, CPLE_OutOfMemory,
769                       "Out of memory in AdoptBlock()." );
770             return CE_Failure;
771         }
772
773         memset( papoBlocks[nSubBlock], 0, nSubGridSize );
774     }
775
776 /* -------------------------------------------------------------------- */
777 /*      Check within subblock.                                          */
778 /* -------------------------------------------------------------------- */
779     GDALRasterBlock **papoSubBlockGrid =
780         (GDALRasterBlock **) papoBlocks[nSubBlock];
781
782     int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff)
783         + WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
784
785     if( papoSubBlockGrid[nBlockInSubBlock] == poBlock )
786         return CE_None;
787
788     if( papoSubBlockGrid[nBlockInSubBlock] != NULL )
789         FlushBlock( nXBlockOff, nYBlockOff );
790
791     papoSubBlockGrid[nBlockInSubBlock] = poBlock;
792     poBlock->Touch();
793
794     return CE_None;
795 }
796
797 /************************************************************************/
798 /*                             FlushCache()                             */
799 /************************************************************************/
800
801 /**
802  * Flush raster data cache.
803  *
804  * This call will recover memory used to cache data blocks for this raster
805  * band, and ensure that new requests are referred to the underlying driver.
806  *
807  * This method is the same as the C function GDALFlushRasterCache().
808  *
809  * @return CE_None on success.
810  */
811
812 CPLErr GDALRasterBand::FlushCache()
813
814 {
815 /* -------------------------------------------------------------------- */
816 /*      Flush all blocks in memory ... this case is without subblocking.*/
817 /* -------------------------------------------------------------------- */
818     if( !bSubBlockingActive )
819     {
820         for( int iY = 0; iY < nBlocksPerColumn; iY++ )
821         {
822             for( int iX = 0; iX < nBlocksPerRow; iX++ )
823             {
824                 if( papoBlocks[iX + iY*nBlocksPerRow] != NULL )
825                 {
826                     CPLErr    eErr;
827
828                     eErr = FlushBlock( iX, iY );
829
830                     if( eErr != CE_None )
831                         return eErr;
832                 }
833             }
834         }
835         return CE_None;
836     }
837
838 /* -------------------------------------------------------------------- */
839 /*      With subblocking.  We can short circuit missing subblocks.      */
840 /* -------------------------------------------------------------------- */
841     int iSBX, iSBY;
842
843     for( iSBY = 0; iSBY < nSubBlocksPerColumn; iSBY++ )
844     {
845         for( iSBX = 0; iSBX < nSubBlocksPerRow; iSBX++ )
846         {
847             int nSubBlock = iSBX + iSBY * nSubBlocksPerRow;
848        
849             GDALRasterBlock **papoSubBlockGrid =
850                 (GDALRasterBlock **) papoBlocks[nSubBlock];
851
852             if( papoSubBlockGrid == NULL )
853                 continue;
854
855             for( int iY = 0; iY < SUBBLOCK_SIZE; iY++ )
856             {
857                 for( int iX = 0; iX < SUBBLOCK_SIZE; iX++ )
858                 {
859                     if( papoSubBlockGrid[iX + iY * SUBBLOCK_SIZE] != NULL )
860                     {
861                         CPLErr eErr;
862
863                         eErr = FlushBlock( iX + iSBX * SUBBLOCK_SIZE,
864                                            iY + iSBY * SUBBLOCK_SIZE );
865                         if( eErr != CE_None )
866                             return eErr;
867                     }
868                 }
869             }
870
871             // We might as well get rid of this grid chunk since we know
872             // it is now empty.
873             papoBlocks[nSubBlock] = NULL;
874             CPLFree( papoSubBlockGrid );
875         }
876     }
877
878     return( CE_None );
879 }
880
881 /************************************************************************/
882 /*                        GDALFlushRasterCache()                        */
883 /************************************************************************/
884
885 /**
886  * @see GDALRasterBand::FlushCache()
887  */
888
889 CPLErr CPL_STDCALL GDALFlushRasterCache( GDALRasterBandH hBand )
890
891 {
892     return ((GDALRasterBand *) hBand)->FlushCache();
893 }
894