1 : /******************************************************************************
2 : * $Id: gtadataset.cpp 23475 2011-12-05 22:44:57Z rouault $
3 : *
4 : * Project: GTA read/write Driver
5 : * Purpose: GDAL bindings over GTA library.
6 : * Author: Martin Lambers, marlam@marlam.de
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, 2011, Martin Lambers <marlam@marlam.de>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : /*
31 : * This driver supports reading and writing GTAs (Generic Tagged Arrays). See
32 : * http://www.nongnu.org/gta/ for details on this format.
33 : *
34 : * Supported Features:
35 : * - CreateCopy().
36 : * - GTA compression can be set.
37 : * - Raster data is updatable for uncompressed GTAs.
38 : * - All input/output is routed through the VSIF*L functions
39 : * (GDAL_DCAP_VIRTUALIO is set to "YES").
40 : * - All kinds of metadata are supported (see tag list below).
41 : *
42 : * Limitations:
43 : * - Only uncompressed GTAs can be updated.
44 : * - Only raster data updates are possible; metadata cannot be changed.
45 : * - Color palettes are not supported.
46 : * - CInt16 is stored as gta::cfloat32, and CInt32 as gta::cfloat64.
47 : * - GDAL metadata is assumed to be in UTF-8 encoding, so that no conversion is
48 : * necessary to store it in GTA tags. I'm not sure that this is correct, but
49 : * since some metadata might not be representable in the local encoding (e.g.
50 : * a chinese description in latin1), using UTF-8 seems reasonable.
51 : *
52 : * The following could be implemented, but currently is not:
53 : * - Allow metadata updates by using a special GDAL/METADATA_BUFFER tag that
54 : * contains a number of spaces as a placeholder for additional metadata, so
55 : * that the header size on disk can be kept constant.
56 : * - Implement Create().
57 : * - Implement AddBand() for uncompressed GTAs. But this would be inefficient:
58 : * the old data would need to be copied to a temporary file, and then copied
59 : * back while extending it with the new band.
60 : * - When strict conversion is requested, store CInt16 in 2 x gta::int16 and
61 : * CInt32 in 2 x gta::int32, and mark these components with special flags so
62 : * that this is reverted when opening the GTA.
63 : * - Support color palettes by storing the palette in special tags.
64 : *
65 : * This driver supports the following standard GTA tags:
66 : * DESCRIPTION
67 : * INTERPRETATION
68 : * NO_DATA_VALUE
69 : * MIN_VALUE
70 : * MAX_VALUE
71 : * UNIT
72 : *
73 : * Additionally, the following tags are used for GDAL-specific metadata:
74 : * GDAL/PROJECTION (WKT)
75 : * GDAL/GEO_TRANSFORM (6 doubles)
76 : * GDAL/OFFSET (1 double)
77 : * GDAL/SCALE (1 double)
78 : * GDAL/GCP_PROJECTION (WKT)
79 : * GDAL/GCP_COUNT (1 int > 0)
80 : * GDAL/GCP%d (5 doubles)
81 : * GDAL/GCP%d_INFO (String)
82 : * GDAL/CATEGORY_COUNT (1 int > 0)
83 : * GDAL/CATEGORY%d (String)
84 : * GDAL/META/DEFAULT/%s (String)
85 : * GDAL/META/RCP/%s (String)
86 : */
87 :
88 : #include <limits.h>
89 : #include "cpl_port.h" // for snprintf for MSVC
90 : #include <gta/gta.hpp>
91 : #include "gdal_pam.h"
92 :
93 : CPL_CVSID("$Id: gtadataset.cpp 23475 2011-12-05 22:44:57Z rouault $");
94 :
95 : CPL_C_START
96 : void GDALRegister_GTA(void);
97 : CPL_C_END
98 :
99 :
100 : /************************************************************************/
101 : /* Helper functions */
102 : /************************************************************************/
103 :
104 108 : static void ScanDoubles( const char *pszString, double *padfDoubles, int nCount )
105 :
106 : {
107 108 : char *pszRemainingString = (char *)pszString;
108 744 : for( int i = 0; i < nCount; i++ )
109 : {
110 636 : padfDoubles[i] = 0.0; // fallback value
111 636 : padfDoubles[i] = CPLStrtod( pszRemainingString, &pszRemainingString );
112 : }
113 108 : }
114 :
115 250 : static CPLString PrintDoubles( const double *padfDoubles, int nCount )
116 :
117 : {
118 250 : CPLString oString;
119 791 : for( int i = 0; i < nCount; i++ )
120 : {
121 541 : oString.FormatC( padfDoubles[i], "%.16g" );
122 541 : if( i < nCount - 1)
123 : {
124 291 : oString += ' ';
125 : }
126 : }
127 0 : return oString;
128 : }
129 :
130 : /************************************************************************/
131 : /* ==================================================================== */
132 : /* GTA custom IO class using GDAL's IO abstraction layer */
133 : /* ==================================================================== */
134 : /************************************************************************/
135 :
136 : class GTAIO : public gta::custom_io
137 : {
138 : private:
139 : VSILFILE *fp;
140 :
141 : public:
142 159 : GTAIO( ) throw ()
143 159 : : fp( NULL )
144 : {
145 159 : }
146 159 : ~GTAIO( )
147 159 : {
148 159 : close( );
149 159 : }
150 :
151 159 : int open( const char *pszFilename, const char *pszMode )
152 : {
153 159 : fp = VSIFOpenL( pszFilename, pszMode );
154 159 : return ( fp == NULL ? -1 : 0 );
155 : }
156 :
157 201 : void close( )
158 : {
159 201 : if( fp != NULL )
160 : {
161 144 : VSIFCloseL( fp );
162 144 : fp = NULL;
163 : }
164 201 : }
165 :
166 102 : vsi_l_offset tell( )
167 : {
168 102 : return VSIFTellL( fp );
169 : }
170 :
171 1205 : virtual size_t read(void *buffer, size_t size, bool *error) throw ()
172 0 : {
173 : size_t s;
174 1205 : s = VSIFReadL( buffer, 1, size, fp );
175 1205 : if( s != size )
176 : {
177 0 : errno = EIO;
178 0 : *error = true;
179 : }
180 1205 : return size;
181 : }
182 :
183 352 : virtual size_t write(const void *buffer, size_t size, bool *error) throw ()
184 0 : {
185 : size_t s;
186 352 : s = VSIFWriteL( buffer, 1, size, fp );
187 352 : if( s != size )
188 : {
189 0 : errno = EIO;
190 0 : *error = true;
191 : }
192 352 : return size;
193 : }
194 :
195 0 : virtual bool seekable() throw ()
196 : {
197 0 : return true;
198 : }
199 :
200 700 : virtual void seek(intmax_t offset, int whence, bool *error) throw ()
201 0 : {
202 : int r;
203 700 : r = VSIFSeekL( fp, offset, whence );
204 700 : if( r != 0 )
205 : {
206 0 : errno = EIO;
207 0 : *error = true;
208 : }
209 700 : }
210 : };
211 :
212 : /************************************************************************/
213 : /* ==================================================================== */
214 : /* GTADataset */
215 : /* ==================================================================== */
216 : /************************************************************************/
217 :
218 : class GTARasterBand;
219 :
220 : class GTADataset : public GDALPamDataset
221 : {
222 : friend class GTARasterBand;
223 :
224 : private:
225 : // GTA input/output via VSIF*L functions
226 : GTAIO oGTAIO;
227 : // GTA information
228 : gta::header oHeader;
229 : vsi_l_offset DataOffset;
230 : // Metadata
231 : bool bHaveGeoTransform;
232 : double adfGeoTransform[6];
233 : int nGCPs;
234 : char *pszGCPProjection;
235 : GDAL_GCP *pasGCPs;
236 : // Cached data block for block-based input/output
237 : int nLastBlockXOff, nLastBlockYOff;
238 : void *pBlock;
239 :
240 : // Block-based input/output of all bands at once. This is used
241 : // by the GTARasterBand input/output functions.
242 : CPLErr ReadBlock( int, int );
243 : CPLErr WriteBlock( );
244 :
245 : public:
246 : GTADataset();
247 : ~GTADataset();
248 :
249 : static GDALDataset *Open( GDALOpenInfo * );
250 :
251 : CPLErr GetGeoTransform( double * padfTransform );
252 : CPLErr SetGeoTransform( double * padfTransform );
253 :
254 : const char *GetProjectionRef( );
255 : CPLErr SetProjection( const char *pszProjection );
256 :
257 : int GetGCPCount( );
258 : const char *GetGCPProjection( );
259 : const GDAL_GCP *GetGCPs( );
260 : CPLErr SetGCPs( int, const GDAL_GCP *, const char * );
261 : };
262 :
263 : /************************************************************************/
264 : /* ==================================================================== */
265 : /* GTARasterBand */
266 : /* ==================================================================== */
267 : /************************************************************************/
268 :
269 : class GTARasterBand : public GDALPamRasterBand
270 : {
271 : friend class GTADataset;
272 : private:
273 : // Size of the component represented by this band
274 : size_t sComponentSize;
275 : // Offset of the component represented by this band inside a GTA element
276 : size_t sComponentOffset;
277 : // StringList for category names
278 : char **papszCategoryNames;
279 : // StringList for metadata
280 : char **papszMetaData;
281 :
282 : public:
283 : GTARasterBand( GTADataset *, int );
284 : ~GTARasterBand( );
285 :
286 : CPLErr IReadBlock( int, int, void * );
287 : CPLErr IWriteBlock( int, int, void * );
288 :
289 : char **GetCategoryNames( );
290 : CPLErr SetCategoryNames( char ** );
291 :
292 : double GetMinimum( int * );
293 : double GetMaximum( int * );
294 :
295 : double GetNoDataValue( int * );
296 : CPLErr SetNoDataValue( double );
297 : double GetOffset( int * );
298 : CPLErr SetOffset( double );
299 : double GetScale( int * );
300 : CPLErr SetScale( double );
301 : const char *GetUnitType( );
302 : CPLErr SetUnitType( const char * );
303 : GDALColorInterp GetColorInterpretation( );
304 : CPLErr SetColorInterpretation( GDALColorInterp );
305 : };
306 :
307 : /************************************************************************/
308 : /* GTARasterBand() */
309 : /************************************************************************/
310 :
311 166 : GTARasterBand::GTARasterBand( GTADataset *poDS, int nBand )
312 :
313 : {
314 166 : this->poDS = poDS;
315 166 : this->nBand = nBand;
316 :
317 : // Data type
318 166 : switch( poDS->oHeader.component_type( nBand-1 ) )
319 : {
320 : case gta::int8:
321 3 : eDataType = GDT_Byte;
322 3 : SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
323 3 : break;
324 : case gta::uint8:
325 125 : eDataType = GDT_Byte;
326 125 : break;
327 : case gta::int16:
328 4 : eDataType = GDT_Int16;
329 4 : break;
330 : case gta::uint16:
331 4 : eDataType = GDT_UInt16;
332 4 : break;
333 : case gta::int32:
334 4 : eDataType = GDT_Int32;
335 4 : break;
336 : case gta::uint32:
337 4 : eDataType = GDT_UInt32;
338 4 : break;
339 : case gta::float32:
340 4 : eDataType = GDT_Float32;
341 4 : break;
342 : case gta::float64:
343 4 : eDataType = GDT_Float64;
344 4 : break;
345 : case gta::cfloat32:
346 7 : eDataType = GDT_CFloat32;
347 7 : break;
348 : case gta::cfloat64:
349 7 : eDataType = GDT_CFloat64;
350 : break;
351 : default:
352 : // cannot happen because we checked this in GTADataset::Open()
353 : break;
354 : }
355 :
356 : // Block size
357 166 : nBlockXSize = poDS->GetRasterXSize();
358 166 : nBlockYSize = 1;
359 :
360 : // Component information
361 166 : sComponentSize = poDS->oHeader.component_size( nBand-1 );
362 166 : sComponentOffset = 0;
363 603 : for( int i = 0; i < nBand-1; i++ )
364 : {
365 437 : sComponentOffset += poDS->oHeader.component_size( i );
366 : }
367 :
368 : // Metadata
369 166 : papszCategoryNames = NULL;
370 166 : papszMetaData = NULL;
371 166 : if( poDS->oHeader.component_taglist( nBand-1 ).get( "DESCRIPTION" ) )
372 : {
373 3 : SetDescription( poDS->oHeader.component_taglist( nBand-1 ).get( "DESCRIPTION" ) );
374 : }
375 689 : for( uintmax_t i = 0; i < poDS->oHeader.component_taglist( nBand-1 ).tags(); i++)
376 : {
377 523 : const char *pszTagName = poDS->oHeader.component_taglist( nBand-1 ).name( i );
378 523 : if( strncmp( pszTagName, "GDAL/META/", 10 ) == 0 )
379 : {
380 12 : const char *pDomainEnd = strchr( pszTagName + 10, '/' );
381 12 : if( pDomainEnd && pDomainEnd - (pszTagName + 10) > 0 )
382 : {
383 12 : char *pszDomain = (char *)VSIMalloc( pDomainEnd - (pszTagName + 10) + 1 );
384 12 : if( !pszDomain )
385 : {
386 0 : continue;
387 : }
388 : int j;
389 96 : for( j = 0; j < pDomainEnd - (pszTagName + 10); j++ )
390 : {
391 84 : pszDomain[j] = pszTagName[10 + j];
392 : }
393 12 : pszDomain[j] = '\0';
394 12 : const char *pszName = pszTagName + 10 + j + 1;
395 12 : const char *pszValue = poDS->oHeader.component_taglist( nBand-1 ).value( i );
396 : SetMetadataItem( pszName, pszValue,
397 12 : strcmp( pszDomain, "DEFAULT" ) == 0 ? NULL : pszDomain );
398 12 : VSIFree( pszDomain );
399 : }
400 : }
401 : }
402 166 : }
403 :
404 : /************************************************************************/
405 : /* ~GTARasterBand() */
406 : /************************************************************************/
407 :
408 166 : GTARasterBand::~GTARasterBand( )
409 :
410 : {
411 166 : CSLDestroy( papszCategoryNames );
412 166 : CSLDestroy( papszMetaData );
413 166 : }
414 :
415 : /************************************************************************/
416 : /* GetCategoryNames() */
417 : /************************************************************************/
418 :
419 2 : char **GTARasterBand::GetCategoryNames( )
420 :
421 : {
422 2 : if( !papszCategoryNames )
423 : {
424 2 : GTADataset *poGDS = (GTADataset *) poDS;
425 2 : const char *pszCatCount = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/CATEGORY_COUNT" );
426 2 : int nCatCount = 0;
427 2 : if( pszCatCount )
428 : {
429 2 : nCatCount = atoi( pszCatCount );
430 : }
431 2 : if( nCatCount > 0 )
432 : {
433 6 : for( int i = 0; i < nCatCount; i++ )
434 : {
435 : const char *pszCatName = poGDS->oHeader.component_taglist( nBand-1 ).get(
436 4 : CPLSPrintf( "GDAL/CATEGORY%d", i ) );
437 4 : papszCategoryNames = CSLAddString( papszCategoryNames, pszCatName ? pszCatName : "" );
438 : }
439 : }
440 : }
441 2 : return papszCategoryNames;
442 : }
443 :
444 : /************************************************************************/
445 : /* SetCategoryName() */
446 : /************************************************************************/
447 :
448 0 : CPLErr GTARasterBand::SetCategoryNames( char ** )
449 :
450 : {
451 : CPLError( CE_Warning, CPLE_NotSupported,
452 0 : "The GTA driver does not support metadata updates.\n" );
453 0 : return CE_Failure;
454 : }
455 :
456 : /************************************************************************/
457 : /* GetMinimum() */
458 : /************************************************************************/
459 :
460 1 : double GTARasterBand::GetMinimum( int *pbSuccess )
461 :
462 : {
463 1 : GTADataset *poGDS = (GTADataset *) poDS;
464 1 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "MIN_VALUE" );
465 1 : if( pszValue )
466 : {
467 1 : if( pbSuccess )
468 1 : *pbSuccess = true;
469 1 : return CPLAtof( pszValue );
470 : }
471 : else
472 : {
473 0 : return GDALRasterBand::GetMinimum( pbSuccess );
474 : }
475 : }
476 :
477 : /************************************************************************/
478 : /* GetMaximum() */
479 : /************************************************************************/
480 :
481 1 : double GTARasterBand::GetMaximum( int *pbSuccess )
482 :
483 : {
484 1 : GTADataset *poGDS = (GTADataset *) poDS;
485 1 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "MAX_VALUE" );
486 1 : if( pszValue )
487 : {
488 1 : if( pbSuccess )
489 1 : *pbSuccess = true;
490 1 : return CPLAtof( pszValue );
491 : }
492 : else
493 : {
494 0 : return GDALRasterBand::GetMaximum( pbSuccess );
495 : }
496 : }
497 :
498 : /************************************************************************/
499 : /* GetNoDataValue() */
500 : /************************************************************************/
501 :
502 28 : double GTARasterBand::GetNoDataValue( int *pbSuccess )
503 :
504 : {
505 28 : GTADataset *poGDS = (GTADataset *) poDS;
506 28 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "NO_DATA_VALUE" );
507 28 : if( pszValue )
508 : {
509 2 : if( pbSuccess )
510 2 : *pbSuccess = true;
511 2 : return CPLAtof( pszValue );
512 : }
513 : else
514 : {
515 26 : return GDALRasterBand::GetNoDataValue( pbSuccess );
516 : }
517 : }
518 :
519 : /************************************************************************/
520 : /* SetNoDataValue() */
521 : /************************************************************************/
522 :
523 0 : CPLErr GTARasterBand::SetNoDataValue( double )
524 :
525 : {
526 : CPLError( CE_Warning, CPLE_NotSupported,
527 0 : "The GTA driver does not support metadata updates.\n" );
528 0 : return CE_Failure;
529 : }
530 :
531 : /************************************************************************/
532 : /* GetOffset() */
533 : /************************************************************************/
534 :
535 71 : double GTARasterBand::GetOffset( int *pbSuccess )
536 :
537 : {
538 71 : GTADataset *poGDS = (GTADataset *) poDS;
539 71 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/OFFSET" );
540 71 : if( pszValue )
541 : {
542 71 : if( pbSuccess )
543 1 : *pbSuccess = true;
544 71 : return CPLAtof( pszValue );
545 : }
546 : else
547 : {
548 0 : return GDALRasterBand::GetOffset( pbSuccess );
549 : }
550 : }
551 :
552 : /************************************************************************/
553 : /* SetOffset() */
554 : /************************************************************************/
555 :
556 0 : CPLErr GTARasterBand::SetOffset( double )
557 :
558 : {
559 : CPLError( CE_Warning, CPLE_NotSupported,
560 0 : "The GTA driver does not support metadata updates.\n" );
561 0 : return CE_Failure;
562 : }
563 :
564 : /************************************************************************/
565 : /* GetScale() */
566 : /************************************************************************/
567 :
568 71 : double GTARasterBand::GetScale( int *pbSuccess )
569 :
570 : {
571 71 : GTADataset *poGDS = (GTADataset *) poDS;
572 71 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/SCALE" );
573 71 : if( pszValue )
574 : {
575 71 : if( pbSuccess )
576 1 : *pbSuccess = true;
577 71 : return CPLAtof( pszValue );
578 : }
579 : else
580 : {
581 0 : return GDALRasterBand::GetScale( pbSuccess );
582 : }
583 : }
584 :
585 : /************************************************************************/
586 : /* SetScale() */
587 : /************************************************************************/
588 :
589 0 : CPLErr GTARasterBand::SetScale( double )
590 :
591 : {
592 : CPLError( CE_Warning, CPLE_NotSupported,
593 0 : "The GTA driver does not support metadata updates.\n" );
594 0 : return CE_Failure;
595 : }
596 :
597 : /************************************************************************/
598 : /* GetUnitType() */
599 : /************************************************************************/
600 :
601 2 : const char *GTARasterBand::GetUnitType( )
602 :
603 : {
604 2 : GTADataset *poGDS = (GTADataset *) poDS;
605 2 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "UNIT" );
606 2 : return pszValue ? pszValue : "";
607 : }
608 :
609 : /************************************************************************/
610 : /* SetUnitType() */
611 : /************************************************************************/
612 :
613 0 : CPLErr GTARasterBand::SetUnitType( const char * )
614 :
615 : {
616 : CPLError( CE_Warning, CPLE_NotSupported,
617 0 : "The GTA driver does not support metadata updates.\n" );
618 0 : return CE_Failure;
619 : }
620 :
621 : /************************************************************************/
622 : /* GetColorInterpretation() */
623 : /************************************************************************/
624 :
625 79 : GDALColorInterp GTARasterBand::GetColorInterpretation( )
626 :
627 : {
628 79 : GTADataset *poGDS = (GTADataset *) poDS;
629 : const char *pszColorInterpretation =
630 : poGDS->oHeader.component_taglist( nBand-1 ).get(
631 79 : "INTERPRETATION" );
632 79 : if( pszColorInterpretation )
633 : {
634 78 : if( EQUAL( pszColorInterpretation, "GRAY" ) )
635 40 : return GCI_GrayIndex ;
636 38 : else if ( EQUAL( pszColorInterpretation, "RED" ) )
637 5 : return GCI_RedBand ;
638 33 : else if ( EQUAL( pszColorInterpretation, "GREEN" ) )
639 5 : return GCI_GreenBand ;
640 28 : else if ( EQUAL( pszColorInterpretation, "BLUE" ) )
641 5 : return GCI_BlueBand ;
642 23 : else if ( EQUAL( pszColorInterpretation, "ALPHA" ) )
643 3 : return GCI_AlphaBand ;
644 20 : else if ( EQUAL( pszColorInterpretation, "HSL/H" ) )
645 2 : return GCI_HueBand ;
646 18 : else if ( EQUAL( pszColorInterpretation, "HSL/S" ) )
647 2 : return GCI_SaturationBand ;
648 16 : else if ( EQUAL( pszColorInterpretation, "HSL/L" ) )
649 2 : return GCI_LightnessBand ;
650 14 : else if ( EQUAL( pszColorInterpretation, "CMYK/C" ) )
651 2 : return GCI_CyanBand ;
652 12 : else if ( EQUAL( pszColorInterpretation, "CMYK/M" ) )
653 2 : return GCI_MagentaBand ;
654 10 : else if ( EQUAL( pszColorInterpretation, "CMYK/Y" ) )
655 2 : return GCI_YellowBand ;
656 8 : else if ( EQUAL( pszColorInterpretation, "CMYK/K" ) )
657 2 : return GCI_BlackBand ;
658 6 : else if ( EQUAL( pszColorInterpretation, "YCBCR/Y" ) )
659 2 : return GCI_YCbCr_YBand;
660 4 : else if ( EQUAL( pszColorInterpretation, "YCBCR/CB" ) )
661 2 : return GCI_YCbCr_CbBand;
662 2 : else if ( EQUAL( pszColorInterpretation, "YCBCR/CR" ) )
663 2 : return GCI_YCbCr_CrBand;
664 : }
665 1 : return GCI_Undefined;
666 : }
667 :
668 : /************************************************************************/
669 : /* SetColorInterpretation() */
670 : /************************************************************************/
671 :
672 0 : CPLErr GTARasterBand::SetColorInterpretation( GDALColorInterp )
673 :
674 : {
675 : CPLError( CE_Warning, CPLE_NotSupported,
676 0 : "The GTA driver does not support metadata updates.\n" );
677 0 : return CE_Failure;
678 : }
679 :
680 : /************************************************************************/
681 : /* IReadBlock() */
682 : /************************************************************************/
683 :
684 620 : CPLErr GTARasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
685 : void * pImage )
686 :
687 : {
688 620 : GTADataset *poGDS = (GTADataset *) poDS;
689 :
690 : // Read and cache block containing all bands at once
691 620 : if( poGDS->ReadBlock( nBlockXOff, nBlockYOff ) != CE_None )
692 : {
693 0 : return CE_Failure;
694 : }
695 :
696 620 : char *pBlock = (char *)poGDS->pBlock;
697 620 : if( poGDS->oHeader.compression() != gta::none )
698 : {
699 : // pBlock contains the complete data set. Add the offset into the
700 : // requested block. This assumes that nBlockYSize == 1 and
701 : // nBlockXSize == nRasterXSize.
702 0 : pBlock += nBlockYOff * nBlockXSize * poGDS->oHeader.element_size();
703 : }
704 :
705 : // Copy the data for this band from the cached block
706 16020 : for( int i = 0; i < nBlockXSize; i++ )
707 : {
708 15400 : char *pSrc = pBlock + i * poGDS->oHeader.element_size() + sComponentOffset;
709 15400 : char *pDst = (char *) pImage + i * sComponentSize;
710 15400 : memcpy( (void *) pDst, (void *) pSrc, sComponentSize );
711 : }
712 :
713 620 : return CE_None;
714 : }
715 :
716 : /************************************************************************/
717 : /* IWriteBlock() */
718 : /************************************************************************/
719 :
720 40 : CPLErr GTARasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
721 : void * pImage )
722 :
723 : {
724 40 : GTADataset *poGDS = (GTADataset *) poDS;
725 :
726 40 : if( poGDS->oHeader.compression() != gta::none )
727 : {
728 : CPLError( CE_Warning, CPLE_NotSupported,
729 0 : "The GTA driver cannot update compressed GTAs.\n" );
730 0 : return CE_Failure;
731 : }
732 :
733 : // Read and cache block containing all bands at once
734 40 : if( poGDS->ReadBlock( nBlockXOff, nBlockYOff ) != CE_None )
735 : {
736 0 : return CE_Failure;
737 : }
738 40 : char *pBlock = (char *)poGDS->pBlock;
739 :
740 : // Copy the data for this band into the cached block
741 840 : for( int i = 0; i < nBlockXSize; i++ )
742 : {
743 800 : char *pSrc = (char *) pImage + i * sComponentSize;
744 800 : char *pDst = pBlock + i * poGDS->oHeader.element_size() + sComponentOffset;
745 800 : memcpy( (void *) pDst, (void *) pSrc, sComponentSize );
746 : }
747 :
748 : // Write the block that conatins all bands at once
749 40 : if( poGDS->WriteBlock( ) != CE_None )
750 : {
751 0 : return CE_Failure;
752 : }
753 :
754 40 : return CE_None;
755 : }
756 :
757 : /************************************************************************/
758 : /* ==================================================================== */
759 : /* GTADataset */
760 : /* ==================================================================== */
761 : /************************************************************************/
762 :
763 : /************************************************************************/
764 : /* GTADataset() */
765 : /************************************************************************/
766 :
767 102 : GTADataset::GTADataset()
768 :
769 : {
770 : // Initialize Metadata
771 102 : bHaveGeoTransform = false;
772 102 : nGCPs = 0;
773 102 : pszGCPProjection = NULL;
774 102 : pasGCPs = NULL;
775 : // Initialize block-based input/output
776 102 : nLastBlockXOff = -1;
777 102 : nLastBlockYOff = -1;
778 102 : pBlock = NULL;
779 102 : }
780 :
781 : /************************************************************************/
782 : /* ~GTADataset() */
783 : /************************************************************************/
784 :
785 102 : GTADataset::~GTADataset()
786 :
787 : {
788 102 : FlushCache();
789 102 : VSIFree( pszGCPProjection );
790 114 : for( int i = 0; i < nGCPs; i++ )
791 : {
792 12 : VSIFree( pasGCPs[i].pszId );
793 12 : VSIFree( pasGCPs[i].pszInfo );
794 : }
795 102 : VSIFree( pasGCPs );
796 102 : VSIFree( pBlock );
797 102 : }
798 :
799 : /************************************************************************/
800 : /* ReadBlock() */
801 : /************************************************************************/
802 :
803 660 : CPLErr GTADataset::ReadBlock( int nBlockXOff, int nBlockYOff )
804 :
805 : {
806 : /* Compressed data sets must be read into memory completely.
807 : * Uncompressed data sets are read block-wise. */
808 :
809 660 : if( oHeader.compression() != gta::none )
810 : {
811 0 : if( pBlock == NULL )
812 : {
813 0 : if( oHeader.data_size() > (size_t)(-1)
814 : || ( pBlock = VSIMalloc( oHeader.data_size() ) ) == NULL )
815 : {
816 : CPLError( CE_Failure, CPLE_OutOfMemory,
817 : "Cannot allocate buffer for the complete data set.\n"
818 : "Try to uncompress the data set to allow block-wise "
819 0 : "reading.\n" );
820 0 : return CE_Failure;
821 : }
822 :
823 : try
824 : {
825 0 : oHeader.read_data( oGTAIO, pBlock );
826 : }
827 0 : catch( gta::exception &e )
828 : {
829 0 : CPLError( CE_Failure, CPLE_FileIO, "GTA error: %s\n", e.what() );
830 0 : return CE_Failure;
831 : }
832 : }
833 : }
834 : else
835 : {
836 : // This has to be the same as in the RasterBand constructor!
837 660 : int nBlockXSize = GetRasterXSize();
838 660 : int nBlockYSize = 1;
839 :
840 660 : if( nLastBlockXOff == nBlockXOff && nLastBlockYOff == nBlockYOff )
841 0 : return CE_None;
842 :
843 660 : if( pBlock == NULL )
844 : {
845 30 : pBlock = VSIMalloc2( oHeader.element_size(), nBlockXSize );
846 30 : if( pBlock == NULL )
847 : {
848 : CPLError( CE_Failure, CPLE_OutOfMemory,
849 0 : "Cannot allocate scanline buffer" );
850 0 : return CE_Failure;
851 : }
852 : }
853 :
854 : try
855 : {
856 660 : uintmax_t lo[2] = { nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize};
857 660 : uintmax_t hi[2] = { lo[0] + nBlockXSize - 1, lo[1] + nBlockYSize - 1 };
858 660 : oHeader.read_block( oGTAIO, DataOffset, lo, hi, pBlock );
859 : }
860 0 : catch( gta::exception &e )
861 : {
862 0 : CPLError( CE_Failure, CPLE_FileIO, "GTA error: %s\n", e.what() );
863 0 : return CE_Failure;
864 : }
865 :
866 660 : nLastBlockXOff = nBlockXOff;
867 660 : nLastBlockYOff = nBlockYOff;
868 : }
869 660 : return CE_None;
870 : }
871 :
872 : /************************************************************************/
873 : /* WriteBlock() */
874 : /************************************************************************/
875 :
876 40 : CPLErr GTADataset::WriteBlock( )
877 :
878 : {
879 : // This has to be the same as in the RasterBand constructor!
880 40 : int nBlockXSize = GetRasterXSize();
881 40 : int nBlockYSize = 1;
882 :
883 : // Write the block (nLastBlockXOff, nLastBlockYOff) stored in pBlock.
884 : try
885 : {
886 40 : uintmax_t lo[2] = { nLastBlockXOff * nBlockXSize, nLastBlockYOff * nBlockYSize};
887 40 : uintmax_t hi[2] = { lo[0] + nBlockXSize - 1, lo[1] + nBlockYSize - 1 };
888 40 : oHeader.write_block( oGTAIO, DataOffset, lo, hi, pBlock );
889 : }
890 0 : catch( gta::exception &e )
891 : {
892 0 : CPLError( CE_Failure, CPLE_FileIO, "GTA error: %s\n", e.what() );
893 0 : return CE_Failure;
894 : }
895 :
896 40 : return CE_None;
897 : }
898 :
899 : /************************************************************************/
900 : /* GetGeoTransform() */
901 : /************************************************************************/
902 :
903 42 : CPLErr GTADataset::GetGeoTransform( double * padfTransform )
904 :
905 : {
906 42 : if( bHaveGeoTransform )
907 : {
908 41 : memcpy( padfTransform, adfGeoTransform, 6*sizeof(double) );
909 41 : return CE_None;
910 : }
911 : else
912 : {
913 1 : return CE_Failure;
914 : }
915 : }
916 :
917 : /************************************************************************/
918 : /* SetGeoTransform() */
919 : /************************************************************************/
920 :
921 0 : CPLErr GTADataset::SetGeoTransform( double * )
922 :
923 : {
924 : CPLError( CE_Warning, CPLE_NotSupported,
925 0 : "The GTA driver does not support metadata updates.\n" );
926 0 : return CE_Failure;
927 : }
928 :
929 : /************************************************************************/
930 : /* GetProjectionRef() */
931 : /************************************************************************/
932 :
933 82 : const char *GTADataset::GetProjectionRef()
934 :
935 : {
936 82 : const char *p = oHeader.global_taglist().get("GDAL/PROJECTION");
937 82 : return ( p ? p : "" );
938 : }
939 :
940 : /************************************************************************/
941 : /* SetProjection() */
942 : /************************************************************************/
943 :
944 0 : CPLErr GTADataset::SetProjection( const char * )
945 :
946 : {
947 : CPLError( CE_Warning, CPLE_NotSupported,
948 0 : "The GTA driver does not support metadata updates.\n" );
949 0 : return CE_Failure;
950 : }
951 :
952 : /************************************************************************/
953 : /* GetGCPCount() */
954 : /************************************************************************/
955 :
956 2 : int GTADataset::GetGCPCount( )
957 :
958 : {
959 2 : return nGCPs;
960 : }
961 :
962 : /************************************************************************/
963 : /* GetGCPProjection() */
964 : /************************************************************************/
965 :
966 1 : const char * GTADataset::GetGCPProjection( )
967 :
968 : {
969 1 : return pszGCPProjection ? pszGCPProjection : "";
970 : }
971 :
972 : /************************************************************************/
973 : /* GetGCPs() */
974 : /************************************************************************/
975 :
976 1 : const GDAL_GCP * GTADataset::GetGCPs( )
977 :
978 : {
979 1 : return pasGCPs;
980 : }
981 :
982 : /************************************************************************/
983 : /* SetGCPs() */
984 : /************************************************************************/
985 :
986 0 : CPLErr GTADataset::SetGCPs( int, const GDAL_GCP *, const char * )
987 :
988 : {
989 : CPLError( CE_Warning, CPLE_NotSupported,
990 0 : "The GTA driver does not support metadata updates.\n" );
991 0 : return CE_Failure;
992 : }
993 :
994 : /************************************************************************/
995 : /* Open() */
996 : /************************************************************************/
997 :
998 14072 : GDALDataset *GTADataset::Open( GDALOpenInfo * poOpenInfo )
999 :
1000 : {
1001 14072 : if( poOpenInfo->nHeaderBytes < 5 )
1002 11989 : return NULL;
1003 :
1004 2083 : if( !EQUALN((char *)poOpenInfo->pabyHeader,"GTA",3) )
1005 1981 : return NULL;
1006 :
1007 : /* -------------------------------------------------------------------- */
1008 : /* Create a corresponding GDALDataset. */
1009 : /* -------------------------------------------------------------------- */
1010 : GTADataset *poDS;
1011 :
1012 102 : poDS = new GTADataset();
1013 :
1014 134 : if( poDS->oGTAIO.open( poOpenInfo->pszFilename,
1015 : poOpenInfo->eAccess == GA_Update ? "r+" : "r" ) != 0 )
1016 : {
1017 0 : CPLError( CE_Failure, CPLE_OpenFailed, "Cannot open file.\n" );
1018 0 : delete poDS;
1019 0 : return NULL;
1020 : }
1021 :
1022 : /* -------------------------------------------------------------------- */
1023 : /* Read the header. */
1024 : /* -------------------------------------------------------------------- */
1025 :
1026 : try
1027 : {
1028 102 : poDS->oHeader.read_from( poDS->oGTAIO );
1029 : }
1030 0 : catch( gta::exception &e )
1031 : {
1032 0 : CPLError( CE_Failure, CPLE_OpenFailed, "GTA error: %s\n", e.what() );
1033 0 : delete poDS;
1034 0 : return NULL;
1035 : }
1036 102 : poDS->DataOffset = poDS->oGTAIO.tell();
1037 102 : poDS->eAccess = poOpenInfo->eAccess;
1038 :
1039 137 : if( poDS->oHeader.compression() != gta::none
1040 : && poOpenInfo->eAccess == GA_Update )
1041 : {
1042 : CPLError( CE_Failure, CPLE_NotSupported,
1043 : "The GTA driver does not support update access to compressed "
1044 0 : "data sets.\nUncompress the data set first.\n" );
1045 0 : delete poDS;
1046 0 : return NULL;
1047 : }
1048 :
1049 102 : if( poDS->oHeader.dimensions() != 2 )
1050 : {
1051 : CPLError( CE_Failure, CPLE_NotSupported,
1052 : "The GTA driver does not support GTAs with %s than 2 "
1053 : "dimensions.\n",
1054 0 : poDS->oHeader.dimensions() < 2 ? "less" : "more" );
1055 0 : delete poDS;
1056 0 : return NULL;
1057 : }
1058 :
1059 : // We know the dimensions are > 0 (guaranteed by libgta), but they may be
1060 : // unrepresentable in GDAL.
1061 102 : if( poDS->oHeader.dimension_size(0) > INT_MAX
1062 : || poDS->oHeader.dimension_size(1) > INT_MAX )
1063 : {
1064 : CPLError( CE_Failure, CPLE_NotSupported,
1065 0 : "The GTA driver does not support the size of this data set.\n" );
1066 0 : delete poDS;
1067 0 : return NULL;
1068 : }
1069 102 : poDS->nRasterXSize = poDS->oHeader.dimension_size(0);
1070 102 : poDS->nRasterYSize = poDS->oHeader.dimension_size(1);
1071 :
1072 : // Check the number of bands (called components in GTA)
1073 102 : if( poDS->oHeader.components() > INT_MAX-1
1074 : || poDS->oHeader.element_size() > ((size_t)-1) )
1075 : {
1076 : CPLError( CE_Failure, CPLE_NotSupported,
1077 : "The GTA driver does not support the number or size of bands "
1078 0 : "in this data set.\n" );
1079 0 : delete poDS;
1080 0 : return NULL;
1081 : }
1082 102 : poDS->nBands = poDS->oHeader.components();
1083 :
1084 : // Check the data types (called component types in GTA)
1085 268 : for( int iBand = 0; iBand < poDS->nBands; iBand++ )
1086 : {
1087 166 : if( poDS->oHeader.component_type(iBand) != gta::uint8
1088 : && poDS->oHeader.component_type(iBand) != gta::int8
1089 : && poDS->oHeader.component_type(iBand) != gta::uint16
1090 : && poDS->oHeader.component_type(iBand) != gta::int16
1091 : && poDS->oHeader.component_type(iBand) != gta::uint32
1092 : && poDS->oHeader.component_type(iBand) != gta::int32
1093 : && poDS->oHeader.component_type(iBand) != gta::float32
1094 : && poDS->oHeader.component_type(iBand) != gta::float64
1095 : && poDS->oHeader.component_type(iBand) != gta::cfloat32
1096 : && poDS->oHeader.component_type(iBand) != gta::cfloat64 )
1097 : {
1098 : CPLError( CE_Failure, CPLE_NotSupported,
1099 : "The GTA driver does not support some of the data types "
1100 0 : "used in this data set.\n" );
1101 0 : delete poDS;
1102 0 : return NULL;
1103 : }
1104 : }
1105 :
1106 : /* -------------------------------------------------------------------- */
1107 : /* Read and set meta information. */
1108 : /* -------------------------------------------------------------------- */
1109 :
1110 102 : if( poDS->oHeader.global_taglist().get("GDAL/GEO_TRANSFORM") )
1111 : {
1112 96 : poDS->bHaveGeoTransform = true;
1113 : ScanDoubles( poDS->oHeader.global_taglist().get( "GDAL/GEO_TRANSFORM" ),
1114 96 : poDS->adfGeoTransform, 6 );
1115 : }
1116 : else
1117 : {
1118 6 : poDS->bHaveGeoTransform = false;
1119 : }
1120 :
1121 102 : if( poDS->oHeader.global_taglist().get("GDAL/GCP_PROJECTION") )
1122 : {
1123 3 : poDS->pszGCPProjection = VSIStrdup( poDS->oHeader.global_taglist().get("GDAL/GCP_PROJECTION") );
1124 : }
1125 102 : if( poDS->oHeader.global_taglist().get("GDAL/GCP_COUNT") )
1126 : {
1127 3 : poDS->nGCPs = atoi( poDS->oHeader.global_taglist().get("GDAL/GCP_COUNT") );
1128 3 : if( poDS->nGCPs < 1 )
1129 : {
1130 0 : poDS->nGCPs = 0;
1131 : }
1132 : else
1133 : {
1134 3 : poDS->pasGCPs = (GDAL_GCP *)VSIMalloc2( poDS->nGCPs, sizeof(GDAL_GCP) );
1135 3 : if( poDS->pasGCPs == NULL )
1136 : {
1137 0 : CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate GCP list" );
1138 0 : delete poDS;
1139 0 : return NULL;
1140 : }
1141 15 : for( int i = 0; i < poDS->nGCPs; i++ )
1142 : {
1143 12 : poDS->pasGCPs[i].pszInfo = NULL;
1144 12 : poDS->pasGCPs[i].dfGCPPixel = 0.0;
1145 12 : poDS->pasGCPs[i].dfGCPLine = 0.0;
1146 12 : poDS->pasGCPs[i].dfGCPX = 0.0;
1147 12 : poDS->pasGCPs[i].dfGCPY = 0.0;
1148 12 : poDS->pasGCPs[i].dfGCPZ = 0.0;
1149 12 : poDS->pasGCPs[i].pszId = VSIStrdup( CPLSPrintf( "%d", i ) );
1150 : char pszGCPTagName[64];
1151 : char pszGCPInfoTagName[64];
1152 12 : strcpy( pszGCPTagName, CPLSPrintf( "GDAL/GCP%d", i ) );
1153 12 : strcpy( pszGCPInfoTagName, CPLSPrintf( "GDAL/GCP%d_INFO", i ) );
1154 12 : if( poDS->oHeader.global_taglist().get(pszGCPInfoTagName) )
1155 : {
1156 0 : poDS->pasGCPs[i].pszInfo = VSIStrdup( poDS->oHeader.global_taglist().get(pszGCPInfoTagName) );
1157 : }
1158 : else
1159 : {
1160 12 : poDS->pasGCPs[i].pszInfo = VSIStrdup( "" );
1161 : }
1162 12 : if( poDS->oHeader.global_taglist().get(pszGCPTagName) )
1163 : {
1164 : double adfTempDoubles[5];
1165 12 : ScanDoubles( poDS->oHeader.global_taglist().get(pszGCPTagName), adfTempDoubles, 5 );
1166 12 : poDS->pasGCPs[i].dfGCPPixel = adfTempDoubles[0];
1167 12 : poDS->pasGCPs[i].dfGCPLine = adfTempDoubles[1];
1168 12 : poDS->pasGCPs[i].dfGCPX = adfTempDoubles[2];
1169 12 : poDS->pasGCPs[i].dfGCPY = adfTempDoubles[3];
1170 12 : poDS->pasGCPs[i].dfGCPZ = adfTempDoubles[4];
1171 : }
1172 : }
1173 : }
1174 : }
1175 :
1176 102 : if( poDS->oHeader.global_taglist().get("DESCRIPTION") )
1177 : {
1178 99 : poDS->SetDescription( poDS->oHeader.global_taglist().get("DESCRIPTION") );
1179 : }
1180 507 : for( uintmax_t i = 0; i < poDS->oHeader.global_taglist().tags(); i++)
1181 : {
1182 405 : const char *pszTagName = poDS->oHeader.global_taglist().name( i );
1183 405 : if( strncmp( pszTagName, "GDAL/META/", 10 ) == 0 )
1184 : {
1185 96 : const char *pDomainEnd = strchr( pszTagName + 10, '/' );
1186 96 : if( pDomainEnd && pDomainEnd - (pszTagName + 10) > 0 )
1187 : {
1188 96 : char *pszDomain = (char *)VSIMalloc( pDomainEnd - (pszTagName + 10) + 1 );
1189 96 : if( !pszDomain )
1190 : {
1191 0 : CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate metadata buffer" );
1192 0 : delete poDS;
1193 0 : return NULL;
1194 : }
1195 : int j;
1196 768 : for( j = 0; j < pDomainEnd - (pszTagName + 10); j++ )
1197 : {
1198 672 : pszDomain[j] = pszTagName[10 + j];
1199 : }
1200 96 : pszDomain[j] = '\0';
1201 96 : const char *pszName = pszTagName + 10 + j + 1;
1202 96 : const char *pszValue = poDS->oHeader.global_taglist().value( i );
1203 : poDS->SetMetadataItem( pszName, pszValue,
1204 96 : strcmp( pszDomain, "DEFAULT" ) == 0 ? NULL : pszDomain );
1205 96 : VSIFree( pszDomain );
1206 : }
1207 : }
1208 : }
1209 :
1210 102 : if( poDS->nBands > 0 )
1211 : {
1212 102 : poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
1213 : }
1214 102 : if( poDS->oHeader.compression() == gta::bzip2 )
1215 3 : poDS->SetMetadataItem( "COMPRESSION", "BZIP2", "IMAGE_STRUCTURE" );
1216 99 : else if( poDS->oHeader.compression() == gta::xz )
1217 3 : poDS->SetMetadataItem( "COMPRESSION", "XZ", "IMAGE_STRUCTURE" );
1218 96 : else if( poDS->oHeader.compression() == gta::zlib )
1219 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB", "IMAGE_STRUCTURE" );
1220 93 : else if( poDS->oHeader.compression() == gta::zlib1 )
1221 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB1", "IMAGE_STRUCTURE" );
1222 90 : else if( poDS->oHeader.compression() == gta::zlib2 )
1223 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB2", "IMAGE_STRUCTURE" );
1224 87 : else if( poDS->oHeader.compression() == gta::zlib3 )
1225 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB3", "IMAGE_STRUCTURE" );
1226 84 : else if( poDS->oHeader.compression() == gta::zlib4 )
1227 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB4", "IMAGE_STRUCTURE" );
1228 81 : else if( poDS->oHeader.compression() == gta::zlib5 )
1229 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB5", "IMAGE_STRUCTURE" );
1230 78 : else if( poDS->oHeader.compression() == gta::zlib6 )
1231 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB6", "IMAGE_STRUCTURE" );
1232 75 : else if( poDS->oHeader.compression() == gta::zlib7 )
1233 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB7", "IMAGE_STRUCTURE" );
1234 72 : else if( poDS->oHeader.compression() == gta::zlib8 )
1235 3 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB8", "IMAGE_STRUCTURE" );
1236 69 : else if( poDS->oHeader.compression() == gta::zlib9 )
1237 2 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB9", "IMAGE_STRUCTURE" );
1238 :
1239 : /* -------------------------------------------------------------------- */
1240 : /* Create band information objects. */
1241 : /* -------------------------------------------------------------------- */
1242 536 : for( int iBand = 0; iBand < poDS->nBands; iBand++ )
1243 : {
1244 166 : poDS->SetBand( iBand+1, new GTARasterBand( poDS, iBand+1 ) );
1245 : }
1246 :
1247 : /* -------------------------------------------------------------------- */
1248 : /* Initialize any PAM information. */
1249 : /* -------------------------------------------------------------------- */
1250 102 : poDS->SetDescription( poOpenInfo->pszFilename );
1251 102 : poDS->TryLoadXML();
1252 :
1253 : /* -------------------------------------------------------------------- */
1254 : /* Check for overviews. */
1255 : /* -------------------------------------------------------------------- */
1256 102 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1257 :
1258 102 : return( poDS );
1259 : }
1260 :
1261 : /************************************************************************/
1262 : /* CreateCopy() */
1263 : /************************************************************************/
1264 :
1265 : static GDALDataset*
1266 60 : GTACreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
1267 : int bStrict, char ** papszOptions,
1268 : GDALProgressFunc pfnProgress, void * pProgressData )
1269 :
1270 : {
1271 60 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
1272 0 : return NULL;
1273 :
1274 : /* -------------------------------------------------------------------- */
1275 : /* Create a GTA header */
1276 : /* -------------------------------------------------------------------- */
1277 :
1278 60 : gta::compression eGTACompression = gta::none;
1279 : const char *pszCompressionValue = CSLFetchNameValue( papszOptions,
1280 60 : "COMPRESS" );
1281 60 : if( pszCompressionValue != NULL )
1282 : {
1283 13 : if( EQUAL( pszCompressionValue, "NONE" ) )
1284 1 : eGTACompression = gta::none;
1285 12 : else if( EQUAL( pszCompressionValue, "BZIP2" ) )
1286 1 : eGTACompression = gta::bzip2;
1287 11 : else if( EQUAL( pszCompressionValue, "XZ" ) )
1288 1 : eGTACompression = gta::xz;
1289 10 : else if( EQUAL( pszCompressionValue, "ZLIB" ))
1290 1 : eGTACompression = gta::zlib;
1291 9 : else if( EQUAL( pszCompressionValue, "ZLIB1" ))
1292 1 : eGTACompression = gta::zlib1;
1293 8 : else if( EQUAL( pszCompressionValue, "ZLIB2" ))
1294 1 : eGTACompression = gta::zlib2;
1295 7 : else if( EQUAL( pszCompressionValue, "ZLIB3" ))
1296 1 : eGTACompression = gta::zlib3;
1297 6 : else if( EQUAL( pszCompressionValue, "ZLIB4" ))
1298 1 : eGTACompression = gta::zlib4;
1299 5 : else if( EQUAL( pszCompressionValue, "ZLIB5" ))
1300 1 : eGTACompression = gta::zlib5;
1301 4 : else if( EQUAL( pszCompressionValue, "ZLIB6" ))
1302 1 : eGTACompression = gta::zlib6;
1303 3 : else if( EQUAL( pszCompressionValue, "ZLIB7" ))
1304 1 : eGTACompression = gta::zlib7;
1305 2 : else if( EQUAL( pszCompressionValue, "ZLIB8" ))
1306 1 : eGTACompression = gta::zlib8;
1307 1 : else if( EQUAL( pszCompressionValue, "ZLIB9" ))
1308 1 : eGTACompression = gta::zlib9;
1309 : else
1310 : CPLError( CE_Warning, CPLE_IllegalArg,
1311 : "COMPRESS=%s value not recognised, ignoring.",
1312 0 : pszCompressionValue );
1313 : }
1314 :
1315 60 : gta::type *peGTATypes = (gta::type *)VSIMalloc2( poSrcDS->GetRasterCount(), sizeof(gta::type) );
1316 60 : if( peGTATypes == NULL )
1317 : {
1318 1 : CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate GTA type list" );
1319 1 : return NULL;
1320 : }
1321 154 : for( int i = 0; i < poSrcDS->GetRasterCount(); i++ )
1322 : {
1323 97 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( i+1 );
1324 97 : if( poSrcBand->GetColorInterpretation() == GCI_PaletteIndex )
1325 : {
1326 : CPLError( CE_Failure, CPLE_NotSupported,
1327 0 : "The GTA driver does not support color palettes.\n" );
1328 0 : VSIFree( peGTATypes );
1329 0 : return NULL;
1330 : }
1331 97 : GDALDataType eDT = poSrcBand->GetRasterDataType();
1332 97 : switch( eDT )
1333 : {
1334 : case GDT_Byte:
1335 : {
1336 69 : const char *pszPixelType = poSrcBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
1337 70 : if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
1338 1 : peGTATypes[i] = gta::int8;
1339 : else
1340 68 : peGTATypes[i] = gta::uint8;
1341 69 : break;
1342 : }
1343 : case GDT_UInt16:
1344 3 : peGTATypes[i] = gta::uint16;
1345 3 : break;
1346 : case GDT_Int16:
1347 3 : peGTATypes[i] = gta::int16;
1348 3 : break;
1349 : case GDT_UInt32:
1350 3 : peGTATypes[i] = gta::uint32;
1351 3 : break;
1352 : case GDT_Int32:
1353 3 : peGTATypes[i] = gta::int32;
1354 3 : break;
1355 : case GDT_Float32:
1356 3 : peGTATypes[i] = gta::float32;
1357 3 : break;
1358 : case GDT_Float64:
1359 3 : peGTATypes[i] = gta::float64;
1360 3 : break;
1361 : case GDT_CInt16:
1362 2 : if( bStrict )
1363 : {
1364 : CPLError( CE_Failure, CPLE_NotSupported,
1365 : "The GTA driver does not support the CInt16 data "
1366 : "type.\n"
1367 : "(If no strict copy is required, the driver can "
1368 1 : "use CFloat32 instead.)\n" );
1369 1 : VSIFree( peGTATypes );
1370 1 : return NULL;
1371 : }
1372 1 : peGTATypes[i] = gta::cfloat32;
1373 1 : break;
1374 : case GDT_CInt32:
1375 2 : if( bStrict )
1376 : {
1377 : CPLError( CE_Failure, CPLE_NotSupported,
1378 : "The GTA driver does not support the CInt32 data "
1379 : "type.\n"
1380 : "(If no strict copy is required, the driver can "
1381 1 : "use CFloat64 instead.)\n" );
1382 1 : VSIFree( peGTATypes );
1383 1 : return NULL;
1384 : }
1385 1 : peGTATypes[i] = gta::cfloat64;
1386 1 : break;
1387 : case GDT_CFloat32:
1388 3 : peGTATypes[i] = gta::cfloat32;
1389 3 : break;
1390 : case GDT_CFloat64:
1391 3 : peGTATypes[i] = gta::cfloat64;
1392 3 : break;
1393 : default:
1394 : CPLError( CE_Failure, CPLE_NotSupported,
1395 : "The GTA driver does not support source data sets using "
1396 0 : "unknown data types.\n");
1397 0 : VSIFree( peGTATypes );
1398 0 : return NULL;
1399 : }
1400 : }
1401 :
1402 57 : gta::header oHeader;
1403 : try
1404 : {
1405 57 : oHeader.set_compression( eGTACompression );
1406 57 : oHeader.set_dimensions( poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize() );
1407 57 : oHeader.set_components( poSrcDS->GetRasterCount(), peGTATypes );
1408 57 : const char *pszDescription = poSrcDS->GetDescription();
1409 : // Metadata from GDALMajorObject
1410 57 : if( pszDescription && pszDescription[0] != '\0' )
1411 : {
1412 56 : oHeader.global_taglist().set( "DESCRIPTION", pszDescription );
1413 : }
1414 57 : const char *papszMetadataDomains[] = { NULL /* default */, "RPC" };
1415 57 : size_t nMetadataDomains = sizeof( papszMetadataDomains ) / sizeof( papszMetadataDomains[0] );
1416 171 : for( size_t iDomain = 0; iDomain < nMetadataDomains; iDomain++ )
1417 : {
1418 114 : char **papszMetadata = poSrcDS->GetMetadata( papszMetadataDomains[iDomain] );
1419 114 : if( papszMetadata )
1420 : {
1421 106 : for( int i = 0; papszMetadata[i]; i++ )
1422 : {
1423 53 : char *pEqualSign = strchr( papszMetadata[i], '=' );
1424 53 : if( pEqualSign && pEqualSign - papszMetadata[i] > 0 )
1425 : {
1426 53 : *pEqualSign = '\0';
1427 : oHeader.global_taglist().set(
1428 : CPLSPrintf( "GDAL/META/%s/%s",
1429 53 : papszMetadataDomains[iDomain] ? papszMetadataDomains[iDomain] : "DEFAULT",
1430 : papszMetadata[i] ),
1431 106 : pEqualSign + 1 );
1432 53 : *pEqualSign = '=';
1433 : }
1434 : }
1435 : }
1436 : }
1437 : // Projection and transformation
1438 57 : const char *pszWKT = poSrcDS->GetProjectionRef();
1439 57 : if( pszWKT && pszWKT[0] != '\0' )
1440 : {
1441 55 : oHeader.global_taglist().set( "GDAL/PROJECTION", pszWKT );
1442 : }
1443 : double adfTransform[6];
1444 57 : if( poSrcDS->GetGeoTransform( adfTransform ) == CE_None )
1445 : {
1446 : oHeader.global_taglist().set( "GDAL/GEO_TRANSFORM",
1447 55 : PrintDoubles( adfTransform, 6 ).c_str() );
1448 : }
1449 : // GCPs
1450 57 : if( poSrcDS->GetGCPCount() > 0 )
1451 : {
1452 1 : oHeader.global_taglist().set( "GDAL/GCP_COUNT", CPLSPrintf( "%d", poSrcDS->GetGCPCount() ) );
1453 1 : oHeader.global_taglist().set( "GDAL/GCP_PROJECTION", poSrcDS->GetGCPProjection() );
1454 1 : const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
1455 5 : for( int i = 0; i < poSrcDS->GetGCPCount(); i++ )
1456 : {
1457 : char pszGCPTagName[64];
1458 : char pszGCPInfoTagName[64];
1459 4 : strcpy( pszGCPTagName, CPLSPrintf( "GDAL/GCP%d", i ) );
1460 4 : strcpy( pszGCPInfoTagName, CPLSPrintf( "GDAL/GCP%d_INFO", i ) );
1461 4 : if( pasGCPs[i].pszInfo && pasGCPs[i].pszInfo[0] != '\0' )
1462 : {
1463 0 : oHeader.global_taglist().set( pszGCPInfoTagName, pasGCPs[i].pszInfo );
1464 : }
1465 : double adfTempDoubles[5];
1466 4 : adfTempDoubles[0] = pasGCPs[i].dfGCPPixel;
1467 4 : adfTempDoubles[1] = pasGCPs[i].dfGCPLine;
1468 4 : adfTempDoubles[2] = pasGCPs[i].dfGCPX;
1469 4 : adfTempDoubles[3] = pasGCPs[i].dfGCPY;
1470 4 : adfTempDoubles[4] = pasGCPs[i].dfGCPZ;
1471 4 : oHeader.global_taglist().set( pszGCPTagName, PrintDoubles( adfTempDoubles, 5 ).c_str() );
1472 : }
1473 : }
1474 : // Now the bands
1475 152 : for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
1476 : {
1477 95 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
1478 : // Metadata from GDALMajorObject
1479 95 : const char *pszBandDescription = poSrcBand->GetDescription();
1480 95 : if( pszBandDescription && pszBandDescription[0] != '\0' )
1481 : {
1482 1 : oHeader.component_taglist( iBand ).set( "DESCRIPTION", pszBandDescription );
1483 : }
1484 285 : for( size_t iDomain = 0; iDomain < nMetadataDomains; iDomain++ )
1485 : {
1486 190 : char **papszBandMetadata = poSrcBand->GetMetadata( papszMetadataDomains[iDomain] );
1487 190 : if( papszBandMetadata )
1488 : {
1489 5 : for( int i = 0; papszBandMetadata[i]; i++ )
1490 : {
1491 4 : char *pEqualSign = strchr( papszBandMetadata[i], '=' );
1492 4 : if( pEqualSign && pEqualSign - papszBandMetadata[i] > 0 )
1493 : {
1494 4 : *pEqualSign = '\0';
1495 : oHeader.component_taglist( iBand ).set(
1496 : CPLSPrintf( "GDAL/META/%s/%s",
1497 4 : papszMetadataDomains[iDomain] ? papszMetadataDomains[iDomain] : "DEFAULT",
1498 : papszBandMetadata[i] ),
1499 8 : pEqualSign + 1 );
1500 4 : *pEqualSign = '=';
1501 : }
1502 : }
1503 : }
1504 : }
1505 : // Category names
1506 95 : char **papszCategoryNames = poSrcBand->GetCategoryNames( );
1507 95 : if( papszCategoryNames )
1508 : {
1509 : int i;
1510 3 : for( i = 0; papszCategoryNames[i]; i++ )
1511 : {
1512 : oHeader.component_taglist( iBand ).set(
1513 : CPLSPrintf( "GDAL/CATEGORY%d", i ),
1514 2 : papszCategoryNames[i] );
1515 : }
1516 : oHeader.component_taglist( iBand ).set(
1517 1 : "GDAL/CATEGORY_COUNT", CPLSPrintf( "%d", i ) );
1518 : }
1519 : // No data value
1520 : int bHaveNoDataValue;
1521 : double dfNoDataValue;
1522 95 : dfNoDataValue = poSrcBand->GetNoDataValue( &bHaveNoDataValue );
1523 95 : if( bHaveNoDataValue )
1524 : oHeader.component_taglist( iBand ).set( "NO_DATA_VALUE",
1525 1 : PrintDoubles( &dfNoDataValue, 1 ).c_str() );
1526 : // Min/max values
1527 : int bHaveMinValue;
1528 : double dfMinValue;
1529 95 : dfMinValue = poSrcBand->GetMinimum( &bHaveMinValue );
1530 95 : if( bHaveMinValue )
1531 : oHeader.component_taglist( iBand ).set( "MIN_VALUE",
1532 1 : PrintDoubles( &dfMinValue, 1 ).c_str() );
1533 : int bHaveMaxValue;
1534 : double dfMaxValue;
1535 95 : dfMaxValue = poSrcBand->GetMaximum( &bHaveMaxValue );
1536 95 : if( bHaveMaxValue )
1537 : oHeader.component_taglist( iBand ).set( "MAX_VALUE",
1538 1 : PrintDoubles( &dfMaxValue, 1 ).c_str() );
1539 : // Offset/scale values
1540 : int bHaveOffsetValue;
1541 : double dfOffsetValue;
1542 95 : dfOffsetValue = poSrcBand->GetOffset( &bHaveOffsetValue );
1543 95 : if( bHaveOffsetValue )
1544 : oHeader.component_taglist( iBand ).set( "GDAL/OFFSET",
1545 94 : PrintDoubles( &dfOffsetValue, 1 ).c_str() );
1546 : int bHaveScaleValue;
1547 : double dfScaleValue;
1548 95 : dfScaleValue = poSrcBand->GetScale( &bHaveScaleValue );
1549 95 : if( bHaveScaleValue )
1550 : oHeader.component_taglist( iBand ).set( "GDAL/SCALE",
1551 94 : PrintDoubles( &dfScaleValue, 1 ).c_str() );
1552 : // Unit
1553 95 : const char *pszUnit = poSrcBand->GetUnitType( );
1554 95 : if( pszUnit != NULL && pszUnit[0] != '\0' )
1555 1 : oHeader.component_taglist( iBand ).set( "UNIT", pszUnit );
1556 : // Color interpretation
1557 95 : GDALColorInterp eCI = poSrcBand->GetColorInterpretation();
1558 95 : if( eCI == GCI_GrayIndex )
1559 52 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "GRAY" );
1560 43 : else if( eCI == GCI_RedBand )
1561 6 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "RED" );
1562 37 : else if( eCI == GCI_GreenBand )
1563 6 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "GREEN" );
1564 31 : else if( eCI == GCI_BlueBand )
1565 6 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "BLUE" );
1566 25 : else if( eCI == GCI_AlphaBand )
1567 3 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "ALPHA" );
1568 22 : else if( eCI == GCI_HueBand )
1569 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/H" );
1570 21 : else if( eCI == GCI_SaturationBand )
1571 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/S" );
1572 20 : else if( eCI == GCI_LightnessBand )
1573 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/L" );
1574 19 : else if( eCI == GCI_CyanBand )
1575 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/C" );
1576 18 : else if( eCI == GCI_MagentaBand )
1577 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/M" );
1578 17 : else if( eCI == GCI_YellowBand )
1579 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/Y" );
1580 16 : else if( eCI == GCI_BlackBand )
1581 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/K" );
1582 15 : else if( eCI == GCI_YCbCr_YBand )
1583 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/Y" );
1584 14 : else if( eCI == GCI_YCbCr_CbBand )
1585 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/CB" );
1586 13 : else if( eCI == GCI_YCbCr_CrBand )
1587 1 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/CR" );
1588 : }
1589 : }
1590 0 : catch( gta::exception &e )
1591 : {
1592 0 : CPLError( CE_Failure, CPLE_NotSupported, "GTA error: %s\n", e.what() );
1593 0 : VSIFree( peGTATypes );
1594 0 : return NULL;
1595 : }
1596 57 : VSIFree( peGTATypes );
1597 :
1598 : /* -------------------------------------------------------------------- */
1599 : /* Write header and data to the file */
1600 : /* -------------------------------------------------------------------- */
1601 :
1602 57 : GTAIO oGTAIO;
1603 57 : if( oGTAIO.open( pszFilename, "w" ) != 0 )
1604 : {
1605 : CPLError( CE_Failure, CPLE_OpenFailed,
1606 15 : "Cannot create GTA file %s.\n", pszFilename );
1607 15 : return NULL;
1608 : }
1609 :
1610 42 : void *pLine = VSIMalloc2( oHeader.element_size(), oHeader.dimension_size(0) );
1611 42 : if( pLine == NULL )
1612 : {
1613 0 : CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate scanline buffer.\n" );
1614 0 : VSIFree( pLine );
1615 0 : return NULL;
1616 : }
1617 :
1618 : try
1619 : {
1620 : // Write header
1621 42 : oHeader.write_to( oGTAIO );
1622 : // Write data line by line
1623 42 : gta::io_state oGTAIOState;
1624 843 : for( int iLine = 0; iLine < poSrcDS->GetRasterYSize(); iLine++ )
1625 : {
1626 801 : size_t nComponentOffset = 0;
1627 1818 : for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
1628 : {
1629 1017 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
1630 1017 : GDALDataType eDT = poSrcBand->GetRasterDataType();
1631 1017 : if( eDT == GDT_CInt16 )
1632 : {
1633 20 : eDT = GDT_CFloat32;
1634 : }
1635 997 : else if( eDT == GDT_CInt32 )
1636 : {
1637 20 : eDT = GDT_CFloat64;
1638 : }
1639 1017 : char *pDst = (char *)pLine + nComponentOffset;
1640 : CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, iLine,
1641 : poSrcDS->GetRasterXSize(), 1,
1642 : pDst, poSrcDS->GetRasterXSize(), 1, eDT,
1643 1017 : oHeader.element_size(), 0 );
1644 1017 : if( eErr != CE_None )
1645 : {
1646 0 : CPLError( CE_Failure, CPLE_FileIO, "Cannot read source data set.\n" );
1647 0 : VSIFree( pLine );
1648 0 : return NULL;
1649 : }
1650 1017 : nComponentOffset += oHeader.component_size( iBand );
1651 : }
1652 801 : oHeader.write_elements( oGTAIOState, oGTAIO, poSrcDS->GetRasterXSize(), pLine );
1653 801 : if( !pfnProgress( (iLine+1) / (double) poSrcDS->GetRasterYSize(),
1654 : NULL, pProgressData ) )
1655 : {
1656 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated CreateCopy()" );
1657 0 : VSIFree( pLine );
1658 0 : return NULL;
1659 : }
1660 0 : }
1661 : }
1662 0 : catch( gta::exception &e )
1663 : {
1664 0 : CPLError( CE_Failure, CPLE_FileIO, "GTA write error: %s\n", e.what() );
1665 0 : VSIFree( pLine );
1666 0 : return NULL;
1667 : }
1668 42 : VSIFree( pLine );
1669 :
1670 42 : oGTAIO.close();
1671 :
1672 : /* -------------------------------------------------------------------- */
1673 : /* Re-open dataset, and copy any auxilary pam information. */
1674 : /* -------------------------------------------------------------------- */
1675 :
1676 : GTADataset *poDS = (GTADataset *) GDALOpen( pszFilename,
1677 42 : eGTACompression == gta::none ? GA_Update : GA_ReadOnly );
1678 :
1679 42 : if( poDS )
1680 42 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1681 :
1682 42 : return poDS;
1683 : }
1684 :
1685 : /************************************************************************/
1686 : /* GDALRegister_GTA() */
1687 : /************************************************************************/
1688 :
1689 582 : void GDALRegister_GTA()
1690 :
1691 : {
1692 : GDALDriver *poDriver;
1693 :
1694 582 : if( GDALGetDriverByName( "GTA" ) == NULL )
1695 : {
1696 561 : poDriver = new GDALDriver();
1697 :
1698 561 : poDriver->SetDescription( "GTA" );
1699 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1700 561 : "Generic Tagged Arrays (.gta)" );
1701 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1702 561 : "frmt_gta.html" );
1703 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gta" );
1704 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1705 : "Byte UInt16 Int16 UInt32 Int32 Float32 Float64 "
1706 561 : "CInt16 CInt32 CFloat32 CFloat64" );
1707 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1708 : "<CreationOptionList>"
1709 : " <Option name='COMPRESS' type='string-select'>"
1710 : " <Value>NONE</Value>"
1711 : " <Value>BZIP2</Value>"
1712 : " <Value>XZ</Value>"
1713 : " <Value>ZLIB</Value>"
1714 : " <Value>ZLIB1</Value>"
1715 : " <Value>ZLIB2</Value>"
1716 : " <Value>ZLIB3</Value>"
1717 : " <Value>ZLIB4</Value>"
1718 : " <Value>ZLIB5</Value>"
1719 : " <Value>ZLIB6</Value>"
1720 : " <Value>ZLIB7</Value>"
1721 : " <Value>ZLIB8</Value>"
1722 : " <Value>ZLIB9</Value>"
1723 : " </Option>"
1724 561 : "</CreationOptionList>" );
1725 :
1726 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1727 :
1728 561 : poDriver->pfnOpen = GTADataset::Open;
1729 561 : poDriver->pfnCreateCopy = GTACreateCopy;
1730 :
1731 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1732 : }
1733 582 : }
|