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 216 : static void ScanDoubles( const char *pszString, double *padfDoubles, int nCount )
105 :
106 : {
107 216 : char *pszRemainingString = (char *)pszString;
108 1488 : for( int i = 0; i < nCount; i++ )
109 : {
110 1272 : padfDoubles[i] = 0.0; // fallback value
111 1272 : padfDoubles[i] = CPLStrtod( pszRemainingString, &pszRemainingString );
112 : }
113 216 : }
114 :
115 382 : static CPLString PrintDoubles( const double *padfDoubles, int nCount )
116 :
117 : {
118 382 : CPLString oString;
119 1216 : for( int i = 0; i < nCount; i++ )
120 : {
121 834 : oString.FormatC( padfDoubles[i], "%.16g" );
122 834 : if( i < nCount - 1)
123 : {
124 452 : 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 292 : GTAIO( ) throw ()
143 292 : : fp( NULL )
144 : {
145 292 : }
146 292 : ~GTAIO( )
147 292 : {
148 292 : close( );
149 292 : }
150 :
151 292 : int open( const char *pszFilename, const char *pszMode )
152 : {
153 292 : fp = VSIFOpenL( pszFilename, pszMode );
154 292 : return ( fp == NULL ? -1 : 0 );
155 : }
156 :
157 376 : void close( )
158 : {
159 376 : if( fp != NULL )
160 : {
161 288 : VSIFCloseL( fp );
162 288 : fp = NULL;
163 : }
164 376 : }
165 :
166 204 : vsi_l_offset tell( )
167 : {
168 204 : return VSIFTellL( fp );
169 : }
170 :
171 2410 : virtual size_t read(void *buffer, size_t size, bool *error) throw ()
172 0 : {
173 : size_t s;
174 2410 : s = VSIFReadL( buffer, 1, size, fp );
175 2410 : if( s != size )
176 : {
177 0 : errno = EIO;
178 0 : *error = true;
179 : }
180 2410 : return size;
181 : }
182 :
183 704 : virtual size_t write(const void *buffer, size_t size, bool *error) throw ()
184 0 : {
185 : size_t s;
186 704 : s = VSIFWriteL( buffer, 1, size, fp );
187 704 : if( s != size )
188 : {
189 0 : errno = EIO;
190 0 : *error = true;
191 : }
192 704 : return size;
193 : }
194 :
195 0 : virtual bool seekable() throw ()
196 : {
197 0 : return true;
198 : }
199 :
200 1400 : virtual void seek(intmax_t offset, int whence, bool *error) throw ()
201 0 : {
202 : int r;
203 1400 : r = VSIFSeekL( fp, offset, whence );
204 1400 : if( r != 0 )
205 : {
206 0 : errno = EIO;
207 0 : *error = true;
208 : }
209 1400 : }
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 332 : GTARasterBand::GTARasterBand( GTADataset *poDS, int nBand )
312 :
313 : {
314 332 : this->poDS = poDS;
315 332 : this->nBand = nBand;
316 :
317 : // Data type
318 332 : switch( poDS->oHeader.component_type( nBand-1 ) )
319 : {
320 : case gta::int8:
321 6 : eDataType = GDT_Byte;
322 6 : SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
323 6 : break;
324 : case gta::uint8:
325 250 : eDataType = GDT_Byte;
326 250 : break;
327 : case gta::int16:
328 8 : eDataType = GDT_Int16;
329 8 : break;
330 : case gta::uint16:
331 8 : eDataType = GDT_UInt16;
332 8 : break;
333 : case gta::int32:
334 8 : eDataType = GDT_Int32;
335 8 : break;
336 : case gta::uint32:
337 8 : eDataType = GDT_UInt32;
338 8 : break;
339 : case gta::float32:
340 8 : eDataType = GDT_Float32;
341 8 : break;
342 : case gta::float64:
343 8 : eDataType = GDT_Float64;
344 8 : break;
345 : case gta::cfloat32:
346 14 : eDataType = GDT_CFloat32;
347 14 : break;
348 : case gta::cfloat64:
349 14 : 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 332 : nBlockXSize = poDS->GetRasterXSize();
358 332 : nBlockYSize = 1;
359 :
360 : // Component information
361 332 : sComponentSize = poDS->oHeader.component_size( nBand-1 );
362 332 : sComponentOffset = 0;
363 1206 : for( int i = 0; i < nBand-1; i++ )
364 : {
365 874 : sComponentOffset += poDS->oHeader.component_size( i );
366 : }
367 :
368 : // Metadata
369 332 : papszCategoryNames = NULL;
370 332 : papszMetaData = NULL;
371 332 : if( poDS->oHeader.component_taglist( nBand-1 ).get( "DESCRIPTION" ) )
372 : {
373 6 : SetDescription( poDS->oHeader.component_taglist( nBand-1 ).get( "DESCRIPTION" ) );
374 : }
375 1378 : for( uintmax_t i = 0; i < poDS->oHeader.component_taglist( nBand-1 ).tags(); i++)
376 : {
377 1046 : const char *pszTagName = poDS->oHeader.component_taglist( nBand-1 ).name( i );
378 1046 : if( strncmp( pszTagName, "GDAL/META/", 10 ) == 0 )
379 : {
380 24 : const char *pDomainEnd = strchr( pszTagName + 10, '/' );
381 24 : if( pDomainEnd && pDomainEnd - (pszTagName + 10) > 0 )
382 : {
383 24 : char *pszDomain = (char *)VSIMalloc( pDomainEnd - (pszTagName + 10) + 1 );
384 24 : if( !pszDomain )
385 : {
386 0 : continue;
387 : }
388 : int j;
389 192 : for( j = 0; j < pDomainEnd - (pszTagName + 10); j++ )
390 : {
391 168 : pszDomain[j] = pszTagName[10 + j];
392 : }
393 24 : pszDomain[j] = '\0';
394 24 : const char *pszName = pszTagName + 10 + j + 1;
395 24 : const char *pszValue = poDS->oHeader.component_taglist( nBand-1 ).value( i );
396 : SetMetadataItem( pszName, pszValue,
397 24 : strcmp( pszDomain, "DEFAULT" ) == 0 ? NULL : pszDomain );
398 24 : VSIFree( pszDomain );
399 : }
400 : }
401 : }
402 332 : }
403 :
404 : /************************************************************************/
405 : /* ~GTARasterBand() */
406 : /************************************************************************/
407 :
408 332 : GTARasterBand::~GTARasterBand( )
409 :
410 : {
411 332 : CSLDestroy( papszCategoryNames );
412 332 : CSLDestroy( papszMetaData );
413 332 : }
414 :
415 : /************************************************************************/
416 : /* GetCategoryNames() */
417 : /************************************************************************/
418 :
419 4 : char **GTARasterBand::GetCategoryNames( )
420 :
421 : {
422 4 : if( !papszCategoryNames )
423 : {
424 4 : GTADataset *poGDS = (GTADataset *) poDS;
425 4 : const char *pszCatCount = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/CATEGORY_COUNT" );
426 4 : int nCatCount = 0;
427 4 : if( pszCatCount )
428 : {
429 4 : nCatCount = atoi( pszCatCount );
430 : }
431 4 : if( nCatCount > 0 )
432 : {
433 12 : for( int i = 0; i < nCatCount; i++ )
434 : {
435 : const char *pszCatName = poGDS->oHeader.component_taglist( nBand-1 ).get(
436 8 : CPLSPrintf( "GDAL/CATEGORY%d", i ) );
437 8 : papszCategoryNames = CSLAddString( papszCategoryNames, pszCatName ? pszCatName : "" );
438 : }
439 : }
440 : }
441 4 : 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 2 : double GTARasterBand::GetMinimum( int *pbSuccess )
461 :
462 : {
463 2 : GTADataset *poGDS = (GTADataset *) poDS;
464 2 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "MIN_VALUE" );
465 2 : if( pszValue )
466 : {
467 2 : if( pbSuccess )
468 2 : *pbSuccess = true;
469 2 : return CPLAtof( pszValue );
470 : }
471 : else
472 : {
473 0 : return GDALRasterBand::GetMinimum( pbSuccess );
474 : }
475 : }
476 :
477 : /************************************************************************/
478 : /* GetMaximum() */
479 : /************************************************************************/
480 :
481 2 : double GTARasterBand::GetMaximum( int *pbSuccess )
482 :
483 : {
484 2 : GTADataset *poGDS = (GTADataset *) poDS;
485 2 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "MAX_VALUE" );
486 2 : if( pszValue )
487 : {
488 2 : if( pbSuccess )
489 2 : *pbSuccess = true;
490 2 : return CPLAtof( pszValue );
491 : }
492 : else
493 : {
494 0 : return GDALRasterBand::GetMaximum( pbSuccess );
495 : }
496 : }
497 :
498 : /************************************************************************/
499 : /* GetNoDataValue() */
500 : /************************************************************************/
501 :
502 56 : double GTARasterBand::GetNoDataValue( int *pbSuccess )
503 :
504 : {
505 56 : GTADataset *poGDS = (GTADataset *) poDS;
506 56 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "NO_DATA_VALUE" );
507 56 : if( pszValue )
508 : {
509 4 : if( pbSuccess )
510 4 : *pbSuccess = true;
511 4 : return CPLAtof( pszValue );
512 : }
513 : else
514 : {
515 52 : 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 142 : double GTARasterBand::GetOffset( int *pbSuccess )
536 :
537 : {
538 142 : GTADataset *poGDS = (GTADataset *) poDS;
539 142 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/OFFSET" );
540 142 : if( pszValue )
541 : {
542 142 : if( pbSuccess )
543 2 : *pbSuccess = true;
544 142 : 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 142 : double GTARasterBand::GetScale( int *pbSuccess )
569 :
570 : {
571 142 : GTADataset *poGDS = (GTADataset *) poDS;
572 142 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/SCALE" );
573 142 : if( pszValue )
574 : {
575 142 : if( pbSuccess )
576 2 : *pbSuccess = true;
577 142 : 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 4 : const char *GTARasterBand::GetUnitType( )
602 :
603 : {
604 4 : GTADataset *poGDS = (GTADataset *) poDS;
605 4 : const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "UNIT" );
606 4 : 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 158 : GDALColorInterp GTARasterBand::GetColorInterpretation( )
626 :
627 : {
628 158 : GTADataset *poGDS = (GTADataset *) poDS;
629 : const char *pszColorInterpretation =
630 : poGDS->oHeader.component_taglist( nBand-1 ).get(
631 158 : "INTERPRETATION" );
632 158 : if( pszColorInterpretation )
633 : {
634 156 : if( EQUAL( pszColorInterpretation, "GRAY" ) )
635 80 : return GCI_GrayIndex ;
636 76 : else if ( EQUAL( pszColorInterpretation, "RED" ) )
637 10 : return GCI_RedBand ;
638 66 : else if ( EQUAL( pszColorInterpretation, "GREEN" ) )
639 10 : return GCI_GreenBand ;
640 56 : else if ( EQUAL( pszColorInterpretation, "BLUE" ) )
641 10 : return GCI_BlueBand ;
642 46 : else if ( EQUAL( pszColorInterpretation, "ALPHA" ) )
643 6 : return GCI_AlphaBand ;
644 40 : else if ( EQUAL( pszColorInterpretation, "HSL/H" ) )
645 4 : return GCI_HueBand ;
646 36 : else if ( EQUAL( pszColorInterpretation, "HSL/S" ) )
647 4 : return GCI_SaturationBand ;
648 32 : else if ( EQUAL( pszColorInterpretation, "HSL/L" ) )
649 4 : return GCI_LightnessBand ;
650 28 : else if ( EQUAL( pszColorInterpretation, "CMYK/C" ) )
651 4 : return GCI_CyanBand ;
652 24 : else if ( EQUAL( pszColorInterpretation, "CMYK/M" ) )
653 4 : return GCI_MagentaBand ;
654 20 : else if ( EQUAL( pszColorInterpretation, "CMYK/Y" ) )
655 4 : return GCI_YellowBand ;
656 16 : else if ( EQUAL( pszColorInterpretation, "CMYK/K" ) )
657 4 : return GCI_BlackBand ;
658 12 : else if ( EQUAL( pszColorInterpretation, "YCBCR/Y" ) )
659 4 : return GCI_YCbCr_YBand;
660 8 : else if ( EQUAL( pszColorInterpretation, "YCBCR/CB" ) )
661 4 : return GCI_YCbCr_CbBand;
662 4 : else if ( EQUAL( pszColorInterpretation, "YCBCR/CR" ) )
663 4 : return GCI_YCbCr_CrBand;
664 : }
665 2 : 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 1240 : CPLErr GTARasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
685 : void * pImage )
686 :
687 : {
688 1240 : GTADataset *poGDS = (GTADataset *) poDS;
689 :
690 : // Read and cache block containing all bands at once
691 1240 : if( poGDS->ReadBlock( nBlockXOff, nBlockYOff ) != CE_None )
692 : {
693 0 : return CE_Failure;
694 : }
695 :
696 1240 : char *pBlock = (char *)poGDS->pBlock;
697 1240 : 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 32040 : for( int i = 0; i < nBlockXSize; i++ )
707 : {
708 30800 : char *pSrc = pBlock + i * poGDS->oHeader.element_size() + sComponentOffset;
709 30800 : char *pDst = (char *) pImage + i * sComponentSize;
710 30800 : memcpy( (void *) pDst, (void *) pSrc, sComponentSize );
711 : }
712 :
713 1240 : return CE_None;
714 : }
715 :
716 : /************************************************************************/
717 : /* IWriteBlock() */
718 : /************************************************************************/
719 :
720 80 : CPLErr GTARasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
721 : void * pImage )
722 :
723 : {
724 80 : GTADataset *poGDS = (GTADataset *) poDS;
725 :
726 80 : 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 80 : if( poGDS->ReadBlock( nBlockXOff, nBlockYOff ) != CE_None )
735 : {
736 0 : return CE_Failure;
737 : }
738 80 : char *pBlock = (char *)poGDS->pBlock;
739 :
740 : // Copy the data for this band into the cached block
741 1680 : for( int i = 0; i < nBlockXSize; i++ )
742 : {
743 1600 : char *pSrc = (char *) pImage + i * sComponentSize;
744 1600 : char *pDst = pBlock + i * poGDS->oHeader.element_size() + sComponentOffset;
745 1600 : memcpy( (void *) pDst, (void *) pSrc, sComponentSize );
746 : }
747 :
748 : // Write the block that conatins all bands at once
749 80 : if( poGDS->WriteBlock( ) != CE_None )
750 : {
751 0 : return CE_Failure;
752 : }
753 :
754 80 : return CE_None;
755 : }
756 :
757 : /************************************************************************/
758 : /* ==================================================================== */
759 : /* GTADataset */
760 : /* ==================================================================== */
761 : /************************************************************************/
762 :
763 : /************************************************************************/
764 : /* GTADataset() */
765 : /************************************************************************/
766 :
767 204 : GTADataset::GTADataset()
768 :
769 : {
770 : // Initialize Metadata
771 204 : bHaveGeoTransform = false;
772 204 : nGCPs = 0;
773 204 : pszGCPProjection = NULL;
774 204 : pasGCPs = NULL;
775 : // Initialize block-based input/output
776 204 : nLastBlockXOff = -1;
777 204 : nLastBlockYOff = -1;
778 204 : pBlock = NULL;
779 204 : }
780 :
781 : /************************************************************************/
782 : /* ~GTADataset() */
783 : /************************************************************************/
784 :
785 204 : GTADataset::~GTADataset()
786 :
787 : {
788 204 : FlushCache();
789 204 : VSIFree( pszGCPProjection );
790 228 : for( int i = 0; i < nGCPs; i++ )
791 : {
792 24 : VSIFree( pasGCPs[i].pszId );
793 24 : VSIFree( pasGCPs[i].pszInfo );
794 : }
795 204 : VSIFree( pasGCPs );
796 204 : VSIFree( pBlock );
797 204 : }
798 :
799 : /************************************************************************/
800 : /* ReadBlock() */
801 : /************************************************************************/
802 :
803 1320 : 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 1320 : 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 1320 : int nBlockXSize = GetRasterXSize();
838 1320 : int nBlockYSize = 1;
839 :
840 1320 : if( nLastBlockXOff == nBlockXOff && nLastBlockYOff == nBlockYOff )
841 0 : return CE_None;
842 :
843 1320 : if( pBlock == NULL )
844 : {
845 60 : pBlock = VSIMalloc2( oHeader.element_size(), nBlockXSize );
846 60 : 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 1320 : uintmax_t lo[2] = { nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize};
857 1320 : uintmax_t hi[2] = { lo[0] + nBlockXSize - 1, lo[1] + nBlockYSize - 1 };
858 1320 : 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 1320 : nLastBlockXOff = nBlockXOff;
867 1320 : nLastBlockYOff = nBlockYOff;
868 : }
869 1320 : return CE_None;
870 : }
871 :
872 : /************************************************************************/
873 : /* WriteBlock() */
874 : /************************************************************************/
875 :
876 80 : CPLErr GTADataset::WriteBlock( )
877 :
878 : {
879 : // This has to be the same as in the RasterBand constructor!
880 80 : int nBlockXSize = GetRasterXSize();
881 80 : int nBlockYSize = 1;
882 :
883 : // Write the block (nLastBlockXOff, nLastBlockYOff) stored in pBlock.
884 : try
885 : {
886 80 : uintmax_t lo[2] = { nLastBlockXOff * nBlockXSize, nLastBlockYOff * nBlockYSize};
887 80 : uintmax_t hi[2] = { lo[0] + nBlockXSize - 1, lo[1] + nBlockYSize - 1 };
888 80 : 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 80 : return CE_None;
897 : }
898 :
899 : /************************************************************************/
900 : /* GetGeoTransform() */
901 : /************************************************************************/
902 :
903 84 : CPLErr GTADataset::GetGeoTransform( double * padfTransform )
904 :
905 : {
906 84 : if( bHaveGeoTransform )
907 : {
908 82 : memcpy( padfTransform, adfGeoTransform, 6*sizeof(double) );
909 82 : return CE_None;
910 : }
911 : else
912 : {
913 2 : 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 164 : const char *GTADataset::GetProjectionRef()
934 :
935 : {
936 164 : const char *p = oHeader.global_taglist().get("GDAL/PROJECTION");
937 164 : 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 4 : int GTADataset::GetGCPCount( )
957 :
958 : {
959 4 : return nGCPs;
960 : }
961 :
962 : /************************************************************************/
963 : /* GetGCPProjection() */
964 : /************************************************************************/
965 :
966 2 : const char * GTADataset::GetGCPProjection( )
967 :
968 : {
969 2 : return pszGCPProjection ? pszGCPProjection : "";
970 : }
971 :
972 : /************************************************************************/
973 : /* GetGCPs() */
974 : /************************************************************************/
975 :
976 2 : const GDAL_GCP * GTADataset::GetGCPs( )
977 :
978 : {
979 2 : 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 26436 : GDALDataset *GTADataset::Open( GDALOpenInfo * poOpenInfo )
999 :
1000 : {
1001 26436 : if( poOpenInfo->nHeaderBytes < 5 )
1002 22488 : return NULL;
1003 :
1004 3948 : if( !EQUALN((char *)poOpenInfo->pabyHeader,"GTA",3) )
1005 3744 : return NULL;
1006 :
1007 : /* -------------------------------------------------------------------- */
1008 : /* Create a corresponding GDALDataset. */
1009 : /* -------------------------------------------------------------------- */
1010 : GTADataset *poDS;
1011 :
1012 204 : poDS = new GTADataset();
1013 :
1014 268 : 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 204 : 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 204 : poDS->DataOffset = poDS->oGTAIO.tell();
1037 204 : poDS->eAccess = poOpenInfo->eAccess;
1038 :
1039 274 : 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 204 : 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 204 : 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 204 : poDS->nRasterXSize = poDS->oHeader.dimension_size(0);
1070 204 : poDS->nRasterYSize = poDS->oHeader.dimension_size(1);
1071 :
1072 : // Check the number of bands (called components in GTA)
1073 204 : 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 204 : poDS->nBands = poDS->oHeader.components();
1083 :
1084 : // Check the data types (called component types in GTA)
1085 536 : for( int iBand = 0; iBand < poDS->nBands; iBand++ )
1086 : {
1087 332 : 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 204 : if( poDS->oHeader.global_taglist().get("GDAL/GEO_TRANSFORM") )
1111 : {
1112 192 : poDS->bHaveGeoTransform = true;
1113 : ScanDoubles( poDS->oHeader.global_taglist().get( "GDAL/GEO_TRANSFORM" ),
1114 192 : poDS->adfGeoTransform, 6 );
1115 : }
1116 : else
1117 : {
1118 12 : poDS->bHaveGeoTransform = false;
1119 : }
1120 :
1121 204 : if( poDS->oHeader.global_taglist().get("GDAL/GCP_PROJECTION") )
1122 : {
1123 6 : poDS->pszGCPProjection = VSIStrdup( poDS->oHeader.global_taglist().get("GDAL/GCP_PROJECTION") );
1124 : }
1125 204 : if( poDS->oHeader.global_taglist().get("GDAL/GCP_COUNT") )
1126 : {
1127 6 : poDS->nGCPs = atoi( poDS->oHeader.global_taglist().get("GDAL/GCP_COUNT") );
1128 6 : if( poDS->nGCPs < 1 )
1129 : {
1130 0 : poDS->nGCPs = 0;
1131 : }
1132 : else
1133 : {
1134 6 : poDS->pasGCPs = (GDAL_GCP *)VSIMalloc2( poDS->nGCPs, sizeof(GDAL_GCP) );
1135 6 : 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 30 : for( int i = 0; i < poDS->nGCPs; i++ )
1142 : {
1143 24 : poDS->pasGCPs[i].pszInfo = NULL;
1144 24 : poDS->pasGCPs[i].dfGCPPixel = 0.0;
1145 24 : poDS->pasGCPs[i].dfGCPLine = 0.0;
1146 24 : poDS->pasGCPs[i].dfGCPX = 0.0;
1147 24 : poDS->pasGCPs[i].dfGCPY = 0.0;
1148 24 : poDS->pasGCPs[i].dfGCPZ = 0.0;
1149 24 : poDS->pasGCPs[i].pszId = VSIStrdup( CPLSPrintf( "%d", i ) );
1150 : char pszGCPTagName[64];
1151 : char pszGCPInfoTagName[64];
1152 24 : strcpy( pszGCPTagName, CPLSPrintf( "GDAL/GCP%d", i ) );
1153 24 : strcpy( pszGCPInfoTagName, CPLSPrintf( "GDAL/GCP%d_INFO", i ) );
1154 24 : 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 24 : poDS->pasGCPs[i].pszInfo = VSIStrdup( "" );
1161 : }
1162 24 : if( poDS->oHeader.global_taglist().get(pszGCPTagName) )
1163 : {
1164 : double adfTempDoubles[5];
1165 24 : ScanDoubles( poDS->oHeader.global_taglist().get(pszGCPTagName), adfTempDoubles, 5 );
1166 24 : poDS->pasGCPs[i].dfGCPPixel = adfTempDoubles[0];
1167 24 : poDS->pasGCPs[i].dfGCPLine = adfTempDoubles[1];
1168 24 : poDS->pasGCPs[i].dfGCPX = adfTempDoubles[2];
1169 24 : poDS->pasGCPs[i].dfGCPY = adfTempDoubles[3];
1170 24 : poDS->pasGCPs[i].dfGCPZ = adfTempDoubles[4];
1171 : }
1172 : }
1173 : }
1174 : }
1175 :
1176 204 : if( poDS->oHeader.global_taglist().get("DESCRIPTION") )
1177 : {
1178 198 : poDS->SetDescription( poDS->oHeader.global_taglist().get("DESCRIPTION") );
1179 : }
1180 996 : for( uintmax_t i = 0; i < poDS->oHeader.global_taglist().tags(); i++)
1181 : {
1182 792 : const char *pszTagName = poDS->oHeader.global_taglist().name( i );
1183 792 : if( strncmp( pszTagName, "GDAL/META/", 10 ) == 0 )
1184 : {
1185 174 : const char *pDomainEnd = strchr( pszTagName + 10, '/' );
1186 174 : if( pDomainEnd && pDomainEnd - (pszTagName + 10) > 0 )
1187 : {
1188 174 : char *pszDomain = (char *)VSIMalloc( pDomainEnd - (pszTagName + 10) + 1 );
1189 174 : 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 1392 : for( j = 0; j < pDomainEnd - (pszTagName + 10); j++ )
1197 : {
1198 1218 : pszDomain[j] = pszTagName[10 + j];
1199 : }
1200 174 : pszDomain[j] = '\0';
1201 174 : const char *pszName = pszTagName + 10 + j + 1;
1202 174 : const char *pszValue = poDS->oHeader.global_taglist().value( i );
1203 : poDS->SetMetadataItem( pszName, pszValue,
1204 174 : strcmp( pszDomain, "DEFAULT" ) == 0 ? NULL : pszDomain );
1205 174 : VSIFree( pszDomain );
1206 : }
1207 : }
1208 : }
1209 :
1210 204 : if( poDS->nBands > 0 )
1211 : {
1212 204 : poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
1213 : }
1214 204 : if( poDS->oHeader.compression() == gta::bzip2 )
1215 6 : poDS->SetMetadataItem( "COMPRESSION", "BZIP2", "IMAGE_STRUCTURE" );
1216 198 : else if( poDS->oHeader.compression() == gta::xz )
1217 6 : poDS->SetMetadataItem( "COMPRESSION", "XZ", "IMAGE_STRUCTURE" );
1218 192 : else if( poDS->oHeader.compression() == gta::zlib )
1219 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB", "IMAGE_STRUCTURE" );
1220 186 : else if( poDS->oHeader.compression() == gta::zlib1 )
1221 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB1", "IMAGE_STRUCTURE" );
1222 180 : else if( poDS->oHeader.compression() == gta::zlib2 )
1223 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB2", "IMAGE_STRUCTURE" );
1224 174 : else if( poDS->oHeader.compression() == gta::zlib3 )
1225 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB3", "IMAGE_STRUCTURE" );
1226 168 : else if( poDS->oHeader.compression() == gta::zlib4 )
1227 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB4", "IMAGE_STRUCTURE" );
1228 162 : else if( poDS->oHeader.compression() == gta::zlib5 )
1229 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB5", "IMAGE_STRUCTURE" );
1230 156 : else if( poDS->oHeader.compression() == gta::zlib6 )
1231 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB6", "IMAGE_STRUCTURE" );
1232 150 : else if( poDS->oHeader.compression() == gta::zlib7 )
1233 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB7", "IMAGE_STRUCTURE" );
1234 144 : else if( poDS->oHeader.compression() == gta::zlib8 )
1235 6 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB8", "IMAGE_STRUCTURE" );
1236 138 : else if( poDS->oHeader.compression() == gta::zlib9 )
1237 4 : poDS->SetMetadataItem( "COMPRESSION", "ZLIB9", "IMAGE_STRUCTURE" );
1238 :
1239 : /* -------------------------------------------------------------------- */
1240 : /* Create band information objects. */
1241 : /* -------------------------------------------------------------------- */
1242 1072 : for( int iBand = 0; iBand < poDS->nBands; iBand++ )
1243 : {
1244 332 : poDS->SetBand( iBand+1, new GTARasterBand( poDS, iBand+1 ) );
1245 : }
1246 :
1247 : /* -------------------------------------------------------------------- */
1248 : /* Initialize any PAM information. */
1249 : /* -------------------------------------------------------------------- */
1250 204 : poDS->SetDescription( poOpenInfo->pszFilename );
1251 204 : poDS->TryLoadXML();
1252 :
1253 : /* -------------------------------------------------------------------- */
1254 : /* Check for overviews. */
1255 : /* -------------------------------------------------------------------- */
1256 204 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1257 :
1258 204 : return( poDS );
1259 : }
1260 :
1261 : /************************************************************************/
1262 : /* CreateCopy() */
1263 : /************************************************************************/
1264 :
1265 : static GDALDataset*
1266 94 : GTACreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
1267 : int bStrict, char ** papszOptions,
1268 : GDALProgressFunc pfnProgress, void * pProgressData )
1269 :
1270 : {
1271 94 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
1272 0 : return NULL;
1273 :
1274 : /* -------------------------------------------------------------------- */
1275 : /* Create a GTA header */
1276 : /* -------------------------------------------------------------------- */
1277 :
1278 94 : gta::compression eGTACompression = gta::none;
1279 : const char *pszCompressionValue = CSLFetchNameValue( papszOptions,
1280 94 : "COMPRESS" );
1281 94 : if( pszCompressionValue != NULL )
1282 : {
1283 26 : if( EQUAL( pszCompressionValue, "NONE" ) )
1284 2 : eGTACompression = gta::none;
1285 24 : else if( EQUAL( pszCompressionValue, "BZIP2" ) )
1286 2 : eGTACompression = gta::bzip2;
1287 22 : else if( EQUAL( pszCompressionValue, "XZ" ) )
1288 2 : eGTACompression = gta::xz;
1289 20 : else if( EQUAL( pszCompressionValue, "ZLIB" ))
1290 2 : eGTACompression = gta::zlib;
1291 18 : else if( EQUAL( pszCompressionValue, "ZLIB1" ))
1292 2 : eGTACompression = gta::zlib1;
1293 16 : else if( EQUAL( pszCompressionValue, "ZLIB2" ))
1294 2 : eGTACompression = gta::zlib2;
1295 14 : else if( EQUAL( pszCompressionValue, "ZLIB3" ))
1296 2 : eGTACompression = gta::zlib3;
1297 12 : else if( EQUAL( pszCompressionValue, "ZLIB4" ))
1298 2 : eGTACompression = gta::zlib4;
1299 10 : else if( EQUAL( pszCompressionValue, "ZLIB5" ))
1300 2 : eGTACompression = gta::zlib5;
1301 8 : else if( EQUAL( pszCompressionValue, "ZLIB6" ))
1302 2 : eGTACompression = gta::zlib6;
1303 6 : else if( EQUAL( pszCompressionValue, "ZLIB7" ))
1304 2 : eGTACompression = gta::zlib7;
1305 4 : else if( EQUAL( pszCompressionValue, "ZLIB8" ))
1306 2 : eGTACompression = gta::zlib8;
1307 2 : else if( EQUAL( pszCompressionValue, "ZLIB9" ))
1308 2 : eGTACompression = gta::zlib9;
1309 : else
1310 : CPLError( CE_Warning, CPLE_IllegalArg,
1311 : "COMPRESS=%s value not recognised, ignoring.",
1312 0 : pszCompressionValue );
1313 : }
1314 :
1315 94 : gta::type *peGTATypes = (gta::type *)VSIMalloc2( poSrcDS->GetRasterCount(), sizeof(gta::type) );
1316 94 : if( peGTATypes == NULL )
1317 : {
1318 2 : CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate GTA type list" );
1319 2 : return NULL;
1320 : }
1321 236 : for( int i = 0; i < poSrcDS->GetRasterCount(); i++ )
1322 : {
1323 148 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( i+1 );
1324 148 : 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 148 : GDALDataType eDT = poSrcBand->GetRasterDataType();
1332 148 : switch( eDT )
1333 : {
1334 : case GDT_Byte:
1335 : {
1336 108 : const char *pszPixelType = poSrcBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
1337 110 : if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
1338 2 : peGTATypes[i] = gta::int8;
1339 : else
1340 106 : peGTATypes[i] = gta::uint8;
1341 108 : break;
1342 : }
1343 : case GDT_UInt16:
1344 4 : peGTATypes[i] = gta::uint16;
1345 4 : break;
1346 : case GDT_Int16:
1347 4 : peGTATypes[i] = gta::int16;
1348 4 : break;
1349 : case GDT_UInt32:
1350 4 : peGTATypes[i] = gta::uint32;
1351 4 : break;
1352 : case GDT_Int32:
1353 4 : peGTATypes[i] = gta::int32;
1354 4 : break;
1355 : case GDT_Float32:
1356 4 : peGTATypes[i] = gta::float32;
1357 4 : break;
1358 : case GDT_Float64:
1359 4 : peGTATypes[i] = gta::float64;
1360 4 : break;
1361 : case GDT_CInt16:
1362 4 : 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 2 : "use CFloat32 instead.)\n" );
1369 2 : VSIFree( peGTATypes );
1370 2 : return NULL;
1371 : }
1372 2 : peGTATypes[i] = gta::cfloat32;
1373 2 : break;
1374 : case GDT_CInt32:
1375 4 : 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 2 : "use CFloat64 instead.)\n" );
1382 2 : VSIFree( peGTATypes );
1383 2 : return NULL;
1384 : }
1385 2 : peGTATypes[i] = gta::cfloat64;
1386 2 : break;
1387 : case GDT_CFloat32:
1388 4 : peGTATypes[i] = gta::cfloat32;
1389 4 : break;
1390 : case GDT_CFloat64:
1391 4 : peGTATypes[i] = gta::cfloat64;
1392 4 : 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 88 : gta::header oHeader;
1403 : try
1404 : {
1405 88 : oHeader.set_compression( eGTACompression );
1406 88 : oHeader.set_dimensions( poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize() );
1407 88 : oHeader.set_components( poSrcDS->GetRasterCount(), peGTATypes );
1408 88 : const char *pszDescription = poSrcDS->GetDescription();
1409 : // Metadata from GDALMajorObject
1410 88 : if( pszDescription && pszDescription[0] != '\0' )
1411 : {
1412 86 : oHeader.global_taglist().set( "DESCRIPTION", pszDescription );
1413 : }
1414 88 : const char *papszMetadataDomains[] = { NULL /* default */, "RPC" };
1415 88 : size_t nMetadataDomains = sizeof( papszMetadataDomains ) / sizeof( papszMetadataDomains[0] );
1416 264 : for( size_t iDomain = 0; iDomain < nMetadataDomains; iDomain++ )
1417 : {
1418 176 : char **papszMetadata = poSrcDS->GetMetadata( papszMetadataDomains[iDomain] );
1419 176 : if( papszMetadata )
1420 : {
1421 152 : for( int i = 0; papszMetadata[i]; i++ )
1422 : {
1423 76 : char *pEqualSign = strchr( papszMetadata[i], '=' );
1424 76 : if( pEqualSign && pEqualSign - papszMetadata[i] > 0 )
1425 : {
1426 76 : *pEqualSign = '\0';
1427 : oHeader.global_taglist().set(
1428 : CPLSPrintf( "GDAL/META/%s/%s",
1429 76 : papszMetadataDomains[iDomain] ? papszMetadataDomains[iDomain] : "DEFAULT",
1430 : papszMetadata[i] ),
1431 152 : pEqualSign + 1 );
1432 76 : *pEqualSign = '=';
1433 : }
1434 : }
1435 : }
1436 : }
1437 : // Projection and transformation
1438 88 : const char *pszWKT = poSrcDS->GetProjectionRef();
1439 88 : if( pszWKT && pszWKT[0] != '\0' )
1440 : {
1441 84 : oHeader.global_taglist().set( "GDAL/PROJECTION", pszWKT );
1442 : }
1443 : double adfTransform[6];
1444 88 : if( poSrcDS->GetGeoTransform( adfTransform ) == CE_None )
1445 : {
1446 : oHeader.global_taglist().set( "GDAL/GEO_TRANSFORM",
1447 84 : PrintDoubles( adfTransform, 6 ).c_str() );
1448 : }
1449 : // GCPs
1450 88 : if( poSrcDS->GetGCPCount() > 0 )
1451 : {
1452 2 : oHeader.global_taglist().set( "GDAL/GCP_COUNT", CPLSPrintf( "%d", poSrcDS->GetGCPCount() ) );
1453 2 : oHeader.global_taglist().set( "GDAL/GCP_PROJECTION", poSrcDS->GetGCPProjection() );
1454 2 : const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
1455 10 : for( int i = 0; i < poSrcDS->GetGCPCount(); i++ )
1456 : {
1457 : char pszGCPTagName[64];
1458 : char pszGCPInfoTagName[64];
1459 8 : strcpy( pszGCPTagName, CPLSPrintf( "GDAL/GCP%d", i ) );
1460 8 : strcpy( pszGCPInfoTagName, CPLSPrintf( "GDAL/GCP%d_INFO", i ) );
1461 8 : 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 8 : adfTempDoubles[0] = pasGCPs[i].dfGCPPixel;
1467 8 : adfTempDoubles[1] = pasGCPs[i].dfGCPLine;
1468 8 : adfTempDoubles[2] = pasGCPs[i].dfGCPX;
1469 8 : adfTempDoubles[3] = pasGCPs[i].dfGCPY;
1470 8 : adfTempDoubles[4] = pasGCPs[i].dfGCPZ;
1471 8 : oHeader.global_taglist().set( pszGCPTagName, PrintDoubles( adfTempDoubles, 5 ).c_str() );
1472 : }
1473 : }
1474 : // Now the bands
1475 232 : for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
1476 : {
1477 144 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
1478 : // Metadata from GDALMajorObject
1479 144 : const char *pszBandDescription = poSrcBand->GetDescription();
1480 144 : if( pszBandDescription && pszBandDescription[0] != '\0' )
1481 : {
1482 2 : oHeader.component_taglist( iBand ).set( "DESCRIPTION", pszBandDescription );
1483 : }
1484 432 : for( size_t iDomain = 0; iDomain < nMetadataDomains; iDomain++ )
1485 : {
1486 288 : char **papszBandMetadata = poSrcBand->GetMetadata( papszMetadataDomains[iDomain] );
1487 288 : if( papszBandMetadata )
1488 : {
1489 10 : for( int i = 0; papszBandMetadata[i]; i++ )
1490 : {
1491 8 : char *pEqualSign = strchr( papszBandMetadata[i], '=' );
1492 8 : if( pEqualSign && pEqualSign - papszBandMetadata[i] > 0 )
1493 : {
1494 8 : *pEqualSign = '\0';
1495 : oHeader.component_taglist( iBand ).set(
1496 : CPLSPrintf( "GDAL/META/%s/%s",
1497 8 : papszMetadataDomains[iDomain] ? papszMetadataDomains[iDomain] : "DEFAULT",
1498 : papszBandMetadata[i] ),
1499 16 : pEqualSign + 1 );
1500 8 : *pEqualSign = '=';
1501 : }
1502 : }
1503 : }
1504 : }
1505 : // Category names
1506 144 : char **papszCategoryNames = poSrcBand->GetCategoryNames( );
1507 144 : if( papszCategoryNames )
1508 : {
1509 : int i;
1510 6 : for( i = 0; papszCategoryNames[i]; i++ )
1511 : {
1512 : oHeader.component_taglist( iBand ).set(
1513 : CPLSPrintf( "GDAL/CATEGORY%d", i ),
1514 4 : papszCategoryNames[i] );
1515 : }
1516 : oHeader.component_taglist( iBand ).set(
1517 2 : "GDAL/CATEGORY_COUNT", CPLSPrintf( "%d", i ) );
1518 : }
1519 : // No data value
1520 : int bHaveNoDataValue;
1521 : double dfNoDataValue;
1522 144 : dfNoDataValue = poSrcBand->GetNoDataValue( &bHaveNoDataValue );
1523 144 : if( bHaveNoDataValue )
1524 : oHeader.component_taglist( iBand ).set( "NO_DATA_VALUE",
1525 2 : PrintDoubles( &dfNoDataValue, 1 ).c_str() );
1526 : // Min/max values
1527 : int bHaveMinValue;
1528 : double dfMinValue;
1529 144 : dfMinValue = poSrcBand->GetMinimum( &bHaveMinValue );
1530 144 : if( bHaveMinValue )
1531 : oHeader.component_taglist( iBand ).set( "MIN_VALUE",
1532 2 : PrintDoubles( &dfMinValue, 1 ).c_str() );
1533 : int bHaveMaxValue;
1534 : double dfMaxValue;
1535 144 : dfMaxValue = poSrcBand->GetMaximum( &bHaveMaxValue );
1536 144 : if( bHaveMaxValue )
1537 : oHeader.component_taglist( iBand ).set( "MAX_VALUE",
1538 2 : PrintDoubles( &dfMaxValue, 1 ).c_str() );
1539 : // Offset/scale values
1540 : int bHaveOffsetValue;
1541 : double dfOffsetValue;
1542 144 : dfOffsetValue = poSrcBand->GetOffset( &bHaveOffsetValue );
1543 144 : if( bHaveOffsetValue )
1544 : oHeader.component_taglist( iBand ).set( "GDAL/OFFSET",
1545 142 : PrintDoubles( &dfOffsetValue, 1 ).c_str() );
1546 : int bHaveScaleValue;
1547 : double dfScaleValue;
1548 144 : dfScaleValue = poSrcBand->GetScale( &bHaveScaleValue );
1549 144 : if( bHaveScaleValue )
1550 : oHeader.component_taglist( iBand ).set( "GDAL/SCALE",
1551 142 : PrintDoubles( &dfScaleValue, 1 ).c_str() );
1552 : // Unit
1553 144 : const char *pszUnit = poSrcBand->GetUnitType( );
1554 144 : if( pszUnit != NULL && pszUnit[0] != '\0' )
1555 2 : oHeader.component_taglist( iBand ).set( "UNIT", pszUnit );
1556 : // Color interpretation
1557 144 : GDALColorInterp eCI = poSrcBand->GetColorInterpretation();
1558 144 : if( eCI == GCI_GrayIndex )
1559 82 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "GRAY" );
1560 62 : else if( eCI == GCI_RedBand )
1561 8 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "RED" );
1562 54 : else if( eCI == GCI_GreenBand )
1563 8 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "GREEN" );
1564 46 : else if( eCI == GCI_BlueBand )
1565 8 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "BLUE" );
1566 38 : else if( eCI == GCI_AlphaBand )
1567 4 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "ALPHA" );
1568 34 : else if( eCI == GCI_HueBand )
1569 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/H" );
1570 32 : else if( eCI == GCI_SaturationBand )
1571 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/S" );
1572 30 : else if( eCI == GCI_LightnessBand )
1573 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/L" );
1574 28 : else if( eCI == GCI_CyanBand )
1575 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/C" );
1576 26 : else if( eCI == GCI_MagentaBand )
1577 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/M" );
1578 24 : else if( eCI == GCI_YellowBand )
1579 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/Y" );
1580 22 : else if( eCI == GCI_BlackBand )
1581 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/K" );
1582 20 : else if( eCI == GCI_YCbCr_YBand )
1583 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/Y" );
1584 18 : else if( eCI == GCI_YCbCr_CbBand )
1585 2 : oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/CB" );
1586 16 : else if( eCI == GCI_YCbCr_CrBand )
1587 2 : 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 88 : VSIFree( peGTATypes );
1597 :
1598 : /* -------------------------------------------------------------------- */
1599 : /* Write header and data to the file */
1600 : /* -------------------------------------------------------------------- */
1601 :
1602 88 : GTAIO oGTAIO;
1603 88 : if( oGTAIO.open( pszFilename, "w" ) != 0 )
1604 : {
1605 : CPLError( CE_Failure, CPLE_OpenFailed,
1606 4 : "Cannot create GTA file %s.\n", pszFilename );
1607 4 : return NULL;
1608 : }
1609 :
1610 84 : void *pLine = VSIMalloc2( oHeader.element_size(), oHeader.dimension_size(0) );
1611 84 : 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 84 : oHeader.write_to( oGTAIO );
1622 : // Write data line by line
1623 84 : gta::io_state oGTAIOState;
1624 1686 : for( int iLine = 0; iLine < poSrcDS->GetRasterYSize(); iLine++ )
1625 : {
1626 1602 : size_t nComponentOffset = 0;
1627 3636 : for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
1628 : {
1629 2034 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
1630 2034 : GDALDataType eDT = poSrcBand->GetRasterDataType();
1631 2034 : if( eDT == GDT_CInt16 )
1632 : {
1633 40 : eDT = GDT_CFloat32;
1634 : }
1635 1994 : else if( eDT == GDT_CInt32 )
1636 : {
1637 40 : eDT = GDT_CFloat64;
1638 : }
1639 2034 : 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 2034 : oHeader.element_size(), 0 );
1644 2034 : 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 2034 : nComponentOffset += oHeader.component_size( iBand );
1651 : }
1652 1602 : oHeader.write_elements( oGTAIOState, oGTAIO, poSrcDS->GetRasterXSize(), pLine );
1653 1602 : 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 84 : VSIFree( pLine );
1669 :
1670 84 : oGTAIO.close();
1671 :
1672 : /* -------------------------------------------------------------------- */
1673 : /* Re-open dataset, and copy any auxilary pam information. */
1674 : /* -------------------------------------------------------------------- */
1675 :
1676 : GTADataset *poDS = (GTADataset *) GDALOpen( pszFilename,
1677 84 : eGTACompression == gta::none ? GA_Update : GA_ReadOnly );
1678 :
1679 84 : if( poDS )
1680 84 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1681 :
1682 84 : return poDS;
1683 : }
1684 :
1685 : /************************************************************************/
1686 : /* GDALRegister_GTA() */
1687 : /************************************************************************/
1688 :
1689 1135 : void GDALRegister_GTA()
1690 :
1691 : {
1692 : GDALDriver *poDriver;
1693 :
1694 1135 : if( GDALGetDriverByName( "GTA" ) == NULL )
1695 : {
1696 1093 : poDriver = new GDALDriver();
1697 :
1698 1093 : poDriver->SetDescription( "GTA" );
1699 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1700 1093 : "Generic Tagged Arrays (.gta)" );
1701 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1702 1093 : "frmt_gta.html" );
1703 1093 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gta" );
1704 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1705 : "Byte UInt16 Int16 UInt32 Int32 Float32 Float64 "
1706 1093 : "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 1093 : "</CreationOptionList>" );
1725 :
1726 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1727 :
1728 1093 : poDriver->pfnOpen = GTADataset::Open;
1729 1093 : poDriver->pfnCreateCopy = GTACreateCopy;
1730 :
1731 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
1732 : }
1733 1135 : }
|