1 /******************************************************************************
2  *
3  * Project:  GDAL Utilities
4  * Purpose:  GDAL Image Translator Program
5  * Author:   Frank Warmerdam, warmerdam@pobox.com
6  *
7  ******************************************************************************
8  * Copyright (c) 1998, 2002, Frank Warmerdam
9  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys.com>
10  * Copyright (c) 2015, Faza Mahamood
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #include "cpl_port.h"
32 #include "gdal_utils.h"
33 #include "gdal_utils_priv.h"
34 
35 #include <cmath>
36 #include <cstdlib>
37 #include <cstring>
38 
39 #include <algorithm>
40 #include <limits>
41 
42 #include "commonutils.h"
43 #include "cpl_conv.h"
44 #include "cpl_error.h"
45 #include "cpl_json.h"
46 #include "cpl_progress.h"
47 #include "cpl_string.h"
48 #include "cpl_vsi.h"
49 #include "gdal.h"
50 #include "gdal_priv.h"
51 #include "gdal_priv_templates.hpp"
52 #include "gdal_rat.h"
53 #include "gdal_vrt.h"
54 #include "ogr_core.h"
55 #include "ogr_spatialref.h"
56 #include "vrtdataset.h"
57 
58 CPL_CVSID("$Id: gdal_translate_lib.cpp e464272048d535fecb3378c0d33efd3e0f8286c8 2021-04-19 22:46:09 +0200 Even Rouault $")
59 
60 static int ArgIsNumeric( const char * );
61 static void AttachMetadata( GDALDatasetH, char ** );
62 static void CopyBandInfo( GDALRasterBand * poSrcBand, GDALRasterBand * poDstBand,
63                           int bCanCopyStatsMetadata, int bCopyScale, int bCopyNoData, bool bCopyRAT,
64                           const GDALTranslateOptions* psOptions );
65 
66 typedef enum
67 {
68     MASK_DISABLED,
69     MASK_AUTO,
70     MASK_USER
71 } MaskMode;
72 
73 /************************************************************************/
74 /*                         GDALTranslateScaleParams                     */
75 /************************************************************************/
76 
77 /** scaling parameters for use in GDALTranslateOptions.
78  */
79 typedef struct
80 {
81     /*! scaling is done only if it is set to TRUE. This is helpful when there is a need to
82         scale only certain bands. */
83     int     bScale;
84 
85     /*! set it to TRUE if dfScaleSrcMin and dfScaleSrcMax is set. When it is FALSE, the
86         input range is automatically computed from the source data. */
87     bool    bHaveScaleSrc;
88 
89     /*! the range of input pixel values which need to be scaled */
90     double dfScaleSrcMin;
91     double dfScaleSrcMax;
92 
93     /*! the range of output pixel values. If GDALTranslateScaleParams::dfScaleDstMin
94         and GDALTranslateScaleParams::dfScaleDstMax are not set, then the output
95         range is 0 to 255. */
96     double dfScaleDstMin;
97     double dfScaleDstMax;
98 } GDALTranslateScaleParams;
99 
100 /************************************************************************/
101 /*                         GDALTranslateOptions                         */
102 /************************************************************************/
103 
104 /** Options for use with GDALTranslate(). GDALTranslateOptions* must be allocated
105  * and freed with GDALTranslateOptionsNew() and GDALTranslateOptionsFree() respectively.
106  */
107 struct GDALTranslateOptions
108 {
109 
110     /*! output format. Use the short format name. */
111     char *pszFormat;
112 
113     /*! allow or suppress progress monitor and other non-error output */
114     bool bQuiet;
115 
116     /*! the progress function to use */
117     GDALProgressFunc pfnProgress;
118 
119     /*! pointer to the progress data variable */
120     void *pProgressData;
121 
122     /*! for the output bands to be of the indicated data type */
123     GDALDataType eOutputType;
124 
125     MaskMode eMaskMode;
126 
127     /*! number of input bands to write to the output file, or to reorder bands */
128     int nBandCount;
129 
130     /*! list of input bands to write to the output file, or to reorder bands. The
131         value 1 corresponds to the 1st band. */
132     int *panBandList; /* negative value of panBandList[i] means mask band of ABS(panBandList[i]) */
133 
134     /*! size of the output file. GDALTranslateOptions::nOXSizePixel is in pixels and
135         GDALTranslateOptions::nOYSizePixel is in lines. If one of the two values is
136         set to 0, its value will be determined from the other one, while maintaining
137         the aspect ratio of the source dataset */
138     int nOXSizePixel;
139     int nOYSizePixel;
140 
141     /*! size of the output file. GDALTranslateOptions::dfOXSizePct and GDALTranslateOptions::dfOYSizePct
142         are fraction of the input image size. The value 100 means 100%. If one of the two values is set
143         to 0, its value will be determined from the other one, while maintaining the aspect ratio of the
144         source dataset */
145     double dfOXSizePct;
146     double dfOYSizePct;
147 
148     /*! list of creation options to the output format driver */
149     char **papszCreateOptions;
150 
151     /*! subwindow from the source image for copying based on pixel/line location */
152     double adfSrcWin[4];
153 
154     /*! don't be forgiving of mismatches and lost data when translating to the output format */
155     bool bStrict;
156 
157     /*! apply the scale/offset metadata for the bands to convert scaled values to unscaled values.
158      *  It is also often necessary to reset the output datatype with GDALTranslateOptions::eOutputType */
159     bool bUnscale;
160 
161     bool bSetScale;
162 
163     double dfScale;
164 
165     bool bSetOffset;
166 
167     double dfOffset;
168 
169     /*! the size of pasScaleParams */
170     int nScaleRepeat;
171 
172     /*! the list of scale parameters for each band. */
173     GDALTranslateScaleParams *pasScaleParams;
174 
175     /*! It is set to TRUE, when scale parameters are specific to each band */
176     bool bHasUsedExplicitScaleBand;
177 
178     /*! the size of the list padfExponent */
179     int nExponentRepeat;
180 
181     /*! to apply non-linear scaling with a power function. It is the list of exponents of the power
182         function (must be positive). This option must be used with GDALTranslateOptions::pasScaleParams. If
183         GDALTranslateOptions::nExponentRepeat is 1, it is applied to all bands of the output image. */
184     double *padfExponent;
185 
186     bool bHasUsedExplicitExponentBand;
187 
188     /*! list of metadata key and value to set on the output dataset if possible.
189      *  GDALTranslateOptionsSetMetadataOptions() and GDALTranslateOptionsAddMetadataOptions()
190      *  should be used */
191     char **papszMetadataOptions;
192 
193     /*! override the projection for the output file. The SRS may be any of the usual
194         GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file containing the WKT. */
195     char *pszOutputSRS;
196 
197     /*! does not copy source GCP into destination dataset (when TRUE) */
198     bool bNoGCP;
199 
200     /*! number of GCPS to be added to the output dataset */
201     int nGCPCount;
202 
203     /*! list of GCPs to be added to the output dataset */
204     GDAL_GCP *pasGCPs;
205 
206     /*! assign/override the georeferenced bounds of the output file. This assigns
207         georeferenced bounds to the output file, ignoring what would have been
208         derived from the source file. So this does not cause reprojection to the
209         specified SRS. */
210     double adfULLR[4];
211 
212     /*! set a nodata value specified in GDALTranslateOptions::dfNoDataReal to the output bands */
213     bool bSetNoData;
214 
215     /*! avoid setting a nodata value to the output file if one exists for the source file */
216     bool bUnsetNoData;
217 
218     /*! Assign a specified nodata value to output bands ( GDALTranslateOptions::bSetNoData option
219         should be set). Note that if the input dataset has a nodata value, this does not cause
220         pixel values that are equal to that nodata value to be changed to the value specified. */
221     double dfNoDataReal;
222 
223     /*! to expose a dataset with 1 band with a color table as a dataset with
224         3 (RGB) or 4 (RGBA) bands. Useful for output drivers such as JPEG,
225         JPEG2000, MrSID, ECW that don't support color indexed datasets.
226         The 1 value enables to expand a dataset with a color table that only
227         contains gray levels to a gray indexed dataset. */
228     int nRGBExpand;
229 
230     int nMaskBand; /* negative value means mask band of ABS(nMaskBand) */
231 
232     /*! force recomputation of statistics */
233     bool bStats;
234 
235     bool bApproxStats;
236 
237     /*! If this option is set, GDALTranslateOptions::adfSrcWin or (GDALTranslateOptions::dfULX,
238         GDALTranslateOptions::dfULY, GDALTranslateOptions::dfLRX, GDALTranslateOptions::dfLRY)
239         values that falls partially outside the source raster extent will be considered
240         as an error. The default behavior is to accept such requests. */
241     bool bErrorOnPartiallyOutside;
242 
243     /*! Same as bErrorOnPartiallyOutside, except that the criterion for
244         erroring out is when the request falls completely outside the
245         source raster extent. */
246     bool bErrorOnCompletelyOutside;
247 
248     /*! does not copy source RAT into destination dataset (when TRUE) */
249     bool bNoRAT;
250 
251     /*! resampling algorithm
252         nearest (default), bilinear, cubic, cubicspline, lanczos, average, mode */
253     char *pszResampling;
254 
255     /*! target resolution. The values must be expressed in georeferenced units.
256         Both must be positive values. This is exclusive with GDALTranslateOptions::nOXSizePixel
257         (or GDALTranslateOptions::dfOXSizePct), GDALTranslateOptions::nOYSizePixel
258         (or GDALTranslateOptions::dfOYSizePct) and GDALTranslateOptions::adfULLR */
259     double dfXRes;
260     double dfYRes;
261 
262     /*! subwindow from the source image for copying (like GDALTranslateOptions::adfSrcWin)
263         but with the corners given in georeferenced coordinates (by default
264         expressed in the SRS of the dataset. Can be changed with
265         pszProjSRS) */
266     double dfULX;
267     double dfULY;
268     double dfLRX;
269     double dfLRY;
270 
271     /*! SRS in which to interpret the coordinates given with GDALTranslateOptions::dfULX,
272         GDALTranslateOptions::dfULY, GDALTranslateOptions::dfLRX, GDALTranslateOptions::dfLRY.
273         The SRS may be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or
274         a file containing the WKT. Note that this does not cause reprojection of the
275         dataset to the specified SRS. */
276     char *pszProjSRS;
277 
278     int nLimitOutSize;
279 
280     // Array of color interpretations per band. Should be a GDALColorInterp
281     // value, or -1 if no override.
282     int nColorInterpSize;
283     int* panColorInterp;
284 
285     /*! does not copy source XMP into destination dataset (when TRUE) */
286     bool bNoXMP;
287 };
288 
289 /************************************************************************/
290 /*                              SrcToDst()                              */
291 /************************************************************************/
292 
SrcToDst(double dfX,double dfY,double dfSrcXOff,double dfSrcYOff,double dfSrcXSize,double dfSrcYSize,double dfDstXOff,double dfDstYOff,double dfDstXSize,double dfDstYSize,double & dfXOut,double & dfYOut)293 static void SrcToDst( double dfX, double dfY,
294                       double dfSrcXOff, double dfSrcYOff,
295                       double dfSrcXSize, double dfSrcYSize,
296                       double dfDstXOff, double dfDstYOff,
297                       double dfDstXSize, double dfDstYSize,
298                       double &dfXOut, double &dfYOut )
299 
300 {
301     dfXOut = ((dfX - dfSrcXOff) / dfSrcXSize) * dfDstXSize + dfDstXOff;
302     dfYOut = ((dfY - dfSrcYOff) / dfSrcYSize) * dfDstYSize + dfDstYOff;
303 }
304 
305 /************************************************************************/
306 /*                          GetSrcDstWindow()                           */
307 /************************************************************************/
308 
FixSrcDstWindow(double * padfSrcWin,double * padfDstWin,int nSrcRasterXSize,int nSrcRasterYSize)309 static bool FixSrcDstWindow( double* padfSrcWin, double* padfDstWin,
310                              int nSrcRasterXSize,
311                              int nSrcRasterYSize )
312 
313 {
314     const double dfSrcXOff = padfSrcWin[0];
315     const double dfSrcYOff = padfSrcWin[1];
316     const double dfSrcXSize = padfSrcWin[2];
317     const double dfSrcYSize = padfSrcWin[3];
318 
319     const double dfDstXOff = padfDstWin[0];
320     const double dfDstYOff = padfDstWin[1];
321     const double dfDstXSize = padfDstWin[2];
322     const double dfDstYSize = padfDstWin[3];
323 
324     bool bModifiedX = false;
325     bool bModifiedY = false;
326 
327     double dfModifiedSrcXOff = dfSrcXOff;
328     double dfModifiedSrcYOff = dfSrcYOff;
329 
330     double dfModifiedSrcXSize = dfSrcXSize;
331     double dfModifiedSrcYSize = dfSrcYSize;
332 
333 /* -------------------------------------------------------------------- */
334 /*      Clamp within the bounds of the available source data.           */
335 /* -------------------------------------------------------------------- */
336     if( dfModifiedSrcXOff < 0 )
337     {
338         dfModifiedSrcXSize += dfModifiedSrcXOff;
339         dfModifiedSrcXOff = 0;
340 
341         bModifiedX = true;
342     }
343 
344     if( dfModifiedSrcYOff < 0 )
345     {
346         dfModifiedSrcYSize += dfModifiedSrcYOff;
347         dfModifiedSrcYOff = 0;
348         bModifiedY = true;
349     }
350 
351     if( dfModifiedSrcXOff + dfModifiedSrcXSize > nSrcRasterXSize )
352     {
353         dfModifiedSrcXSize = nSrcRasterXSize - dfModifiedSrcXOff;
354         bModifiedX = true;
355     }
356 
357     if( dfModifiedSrcYOff + dfModifiedSrcYSize > nSrcRasterYSize )
358     {
359         dfModifiedSrcYSize = nSrcRasterYSize - dfModifiedSrcYOff;
360         bModifiedY = true;
361     }
362 
363 /* -------------------------------------------------------------------- */
364 /*      Don't do anything if the requesting region is completely off    */
365 /*      the source image.                                               */
366 /* -------------------------------------------------------------------- */
367     if( dfModifiedSrcXOff >= nSrcRasterXSize
368         || dfModifiedSrcYOff >= nSrcRasterYSize
369         || dfModifiedSrcXSize <= 0 || dfModifiedSrcYSize <= 0 )
370     {
371         return false;
372     }
373 
374     padfSrcWin[0] = dfModifiedSrcXOff;
375     padfSrcWin[1] = dfModifiedSrcYOff;
376     padfSrcWin[2] = dfModifiedSrcXSize;
377     padfSrcWin[3] = dfModifiedSrcYSize;
378 
379 /* -------------------------------------------------------------------- */
380 /*      If we haven't had to modify the source rectangle, then the      */
381 /*      destination rectangle must be the whole region.                 */
382 /* -------------------------------------------------------------------- */
383     if( !bModifiedX && !bModifiedY )
384         return true;
385 
386 /* -------------------------------------------------------------------- */
387 /*      Now transform this possibly reduced request back into the       */
388 /*      destination buffer coordinates in case the output region is     */
389 /*      less than the whole buffer.                                     */
390 /* -------------------------------------------------------------------- */
391     double dfDstULX, dfDstULY, dfDstLRX, dfDstLRY;
392 
393     SrcToDst( dfModifiedSrcXOff, dfModifiedSrcYOff,
394               dfSrcXOff, dfSrcYOff,
395               dfSrcXSize, dfSrcYSize,
396               dfDstXOff, dfDstYOff,
397               dfDstXSize, dfDstYSize,
398               dfDstULX, dfDstULY );
399     SrcToDst( dfModifiedSrcXOff + dfModifiedSrcXSize, dfModifiedSrcYOff + dfModifiedSrcYSize,
400               dfSrcXOff, dfSrcYOff,
401               dfSrcXSize, dfSrcYSize,
402               dfDstXOff, dfDstYOff,
403               dfDstXSize, dfDstYSize,
404               dfDstLRX, dfDstLRY );
405 
406     double dfModifiedDstXOff = dfDstXOff;
407     double dfModifiedDstYOff = dfDstYOff;
408     double dfModifiedDstXSize = dfDstXSize;
409     double dfModifiedDstYSize = dfDstYSize;
410 
411     if( bModifiedX )
412     {
413         dfModifiedDstXOff = dfDstULX - dfDstXOff;
414         dfModifiedDstXSize = (dfDstLRX - dfDstXOff) - dfModifiedDstXOff;
415 
416         dfModifiedDstXOff = std::max(0.0, dfModifiedDstXOff);
417         if( dfModifiedDstXOff + dfModifiedDstXSize > dfDstXSize )
418             dfModifiedDstXSize = dfDstXSize - dfModifiedDstXOff;
419     }
420 
421     if( bModifiedY )
422     {
423         dfModifiedDstYOff = dfDstULY - dfDstYOff;
424         dfModifiedDstYSize = (dfDstLRY - dfDstYOff) - dfModifiedDstYOff;
425 
426         dfModifiedDstYOff = std::max(0.0, dfModifiedDstYOff);
427         if( dfModifiedDstYOff + dfModifiedDstYSize > dfDstYSize )
428             dfModifiedDstYSize = dfDstYSize - dfModifiedDstYOff;
429     }
430 
431     if( dfModifiedDstXSize <= 0.0 || dfModifiedDstYSize <= 0.0 )
432     {
433         return false;
434     }
435 
436     padfDstWin[0] = dfModifiedDstXOff;
437     padfDstWin[1] = dfModifiedDstYOff;
438     padfDstWin[2] = dfModifiedDstXSize;
439     padfDstWin[3] = dfModifiedDstYSize;
440 
441     return true;
442 }
443 
444 /************************************************************************/
445 /*                          GDALTranslateOptionsClone()                 */
446 /************************************************************************/
447 
448 static
GDALTranslateOptionsClone(const GDALTranslateOptions * psOptionsIn)449 GDALTranslateOptions* GDALTranslateOptionsClone(const GDALTranslateOptions *psOptionsIn)
450 {
451     GDALTranslateOptions* psOptions = static_cast<GDALTranslateOptions*>(
452         CPLMalloc(sizeof(GDALTranslateOptions)));
453     memcpy(psOptions, psOptionsIn, sizeof(GDALTranslateOptions));
454     if( psOptionsIn->pszFormat ) psOptions->pszFormat = CPLStrdup(psOptionsIn->pszFormat);
455     if( psOptionsIn->panBandList )
456     {
457         psOptions->panBandList =
458             static_cast<int *>(CPLMalloc(sizeof(int) * psOptions->nBandCount));
459         memcpy(psOptions->panBandList, psOptionsIn->panBandList,
460                sizeof(int) * psOptions->nBandCount);
461     }
462     psOptions->papszCreateOptions = CSLDuplicate(psOptionsIn->papszCreateOptions);
463     if( psOptionsIn->pasScaleParams )
464     {
465         psOptions->pasScaleParams = static_cast<GDALTranslateScaleParams *>(
466             CPLMalloc(sizeof(GDALTranslateScaleParams) *
467                       psOptions->nScaleRepeat));
468         memcpy(psOptions->pasScaleParams, psOptionsIn->pasScaleParams,
469                sizeof(GDALTranslateScaleParams) * psOptions->nScaleRepeat);
470     }
471     if( psOptionsIn->padfExponent )
472     {
473         psOptions->padfExponent = static_cast<double *>(
474             CPLMalloc(sizeof(double) * psOptions->nExponentRepeat));
475         memcpy(psOptions->padfExponent, psOptionsIn->padfExponent,
476                sizeof(double) * psOptions->nExponentRepeat);
477     }
478     psOptions->papszMetadataOptions = CSLDuplicate(psOptionsIn->papszMetadataOptions);
479     if( psOptionsIn->pszOutputSRS ) psOptions->pszOutputSRS = CPLStrdup(psOptionsIn->pszOutputSRS);
480     if( psOptionsIn->nGCPCount )
481         psOptions->pasGCPs = GDALDuplicateGCPs( psOptionsIn->nGCPCount, psOptionsIn->pasGCPs );
482     if( psOptionsIn->pszResampling ) psOptions->pszResampling = CPLStrdup(psOptionsIn->pszResampling);
483     if( psOptionsIn->pszProjSRS ) psOptions->pszProjSRS = CPLStrdup(psOptionsIn->pszProjSRS);
484     if( psOptionsIn->panColorInterp )
485     {
486         psOptions->panColorInterp =
487             static_cast<int *>(CPLMalloc(sizeof(int) * psOptions->nColorInterpSize));
488         memcpy(psOptions->panColorInterp, psOptionsIn->panColorInterp,
489                sizeof(int) * psOptions->nColorInterpSize);
490     }
491     return psOptions;
492 }
493 
494 /************************************************************************/
495 /*                        GDALTranslateFlush()                          */
496 /************************************************************************/
497 
GDALTranslateFlush(GDALDatasetH hOutDS)498 static GDALDatasetH GDALTranslateFlush(GDALDatasetH hOutDS)
499 {
500     if( hOutDS != nullptr )
501     {
502         CPLErr eErrBefore = CPLGetLastErrorType();
503         GDALFlushCache( hOutDS );
504         if (eErrBefore == CE_None &&
505             CPLGetLastErrorType() != CE_None)
506         {
507             GDALClose(hOutDS);
508             hOutDS = nullptr;
509         }
510     }
511     return hOutDS;
512 }
513 
514 /************************************************************************/
515 /*                    EditISIS3MetadataForBandChange()                  */
516 /************************************************************************/
517 
Clone(const CPLJSONObject & obj)518 static CPLJSONObject Clone(const CPLJSONObject& obj)
519 {
520     auto serialized = obj.Format(CPLJSONObject::PrettyFormat::Plain);
521     CPLJSONDocument oJSONDocument;
522     const GByte *pabyData = reinterpret_cast<const GByte *>(serialized.c_str());
523     oJSONDocument.LoadMemory( pabyData );
524     return oJSONDocument.GetRoot();
525 }
526 
ReworkArray(CPLJSONObject & container,const CPLJSONObject & obj,int nSrcBandCount,const GDALTranslateOptions * psOptions)527 static void ReworkArray(CPLJSONObject& container, const CPLJSONObject& obj,
528                         int nSrcBandCount,
529                         const GDALTranslateOptions *psOptions)
530 {
531     auto oArray = obj.ToArray();
532     if( oArray.Size() == nSrcBandCount )
533     {
534         CPLJSONArray oNewArray;
535         for( int i = 0; i < psOptions->nBandCount; i++ )
536         {
537             const int iSrcIdx = psOptions->panBandList[i]-1;
538             oNewArray.Add(oArray[iSrcIdx]);
539         }
540         const auto childName(obj.GetName());
541         container.Delete(childName);
542         container.Add(childName, oNewArray);
543     }
544 }
545 
EditISIS3MetadataForBandChange(const char * pszJSON,int nSrcBandCount,const GDALTranslateOptions * psOptions)546 static CPLString EditISIS3MetadataForBandChange(const char* pszJSON,
547                                                 int nSrcBandCount,
548                                                 const GDALTranslateOptions *psOptions)
549 {
550     CPLJSONDocument oJSONDocument;
551     const GByte *pabyData = reinterpret_cast<const GByte *>(pszJSON);
552     if( !oJSONDocument.LoadMemory( pabyData ) )
553     {
554         return CPLString();
555     }
556 
557     auto oRoot = oJSONDocument.GetRoot();
558     if( !oRoot.IsValid() )
559     {
560         return CPLString();
561     }
562 
563     auto oBandBin = oRoot.GetObj( "IsisCube/BandBin" );
564     if( oBandBin.IsValid() && oBandBin.GetType() == CPLJSONObject::Type::Object )
565     {
566         // Backup original BandBin object
567         oRoot.GetObj("IsisCube").Add("OriginalBandBin", Clone(oBandBin));
568 
569         // Iterate over BandBin members and reorder/resize its arrays that
570         // have the same number of elements than the number of bands of the
571         // source dataset.
572         for( auto& child: oBandBin.GetChildren() )
573         {
574             if( child.GetType() == CPLJSONObject::Type::Array )
575             {
576                 ReworkArray(oBandBin, child, nSrcBandCount, psOptions);
577             }
578             else if( child.GetType() == CPLJSONObject::Type::Object )
579             {
580                 auto oValue = child.GetObj("value");
581                 auto oUnit = child.GetObj("unit");
582                 if( oValue.GetType() == CPLJSONObject::Type::Array )
583                 {
584                     ReworkArray(child, oValue, nSrcBandCount, psOptions);
585                 }
586             }
587         }
588     }
589 
590     return oRoot.Format(CPLJSONObject::PrettyFormat::Pretty);
591 }
592 
593 /************************************************************************/
594 /*                       AdjustNoDataValue()                            */
595 /************************************************************************/
596 
AdjustNoDataValue(double dfInputNoDataValue,GDALRasterBand * poBand,const GDALTranslateOptions * psOptions)597 static double AdjustNoDataValue( double dfInputNoDataValue,
598                                  GDALRasterBand* poBand,
599                                  const GDALTranslateOptions *psOptions )
600 {
601     bool bSignedByte = false;
602     const char* pszPixelType = CSLFetchNameValue( psOptions->papszCreateOptions, "PIXELTYPE" );
603     if( pszPixelType == nullptr )
604     {
605         pszPixelType = poBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
606     }
607     if( pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE") )
608         bSignedByte = true;
609     int bClamped = FALSE;
610     int bRounded = FALSE;
611     double dfVal = 0.0;
612     const GDALDataType eBandType = poBand->GetRasterDataType();
613     if( bSignedByte )
614     {
615         if( dfInputNoDataValue < -128.0 )
616         {
617             dfVal = -128.0;
618             bClamped = TRUE;
619         }
620         else if( dfInputNoDataValue > 127.0 )
621         {
622             dfVal = 127.0;
623             bClamped = TRUE;
624         }
625         else
626         {
627             dfVal = static_cast<int>(floor(dfInputNoDataValue + 0.5));
628             if( dfVal != dfInputNoDataValue )
629                 bRounded = TRUE;
630         }
631     }
632     else
633     {
634         dfVal = GDALAdjustValueToDataType(eBandType,
635                                                 dfInputNoDataValue,
636                                                 &bClamped, &bRounded );
637     }
638 
639     if (bClamped)
640     {
641         CPLError( CE_Warning, CPLE_AppDefined, "for band %d, nodata value has been clamped "
642                 "to %.0f, the original value being out of range.",
643                 poBand->GetBand(), dfVal);
644     }
645     else if(bRounded)
646     {
647         CPLError( CE_Warning, CPLE_AppDefined, "for band %d, nodata value has been rounded "
648                 "to %.0f, %s being an integer datatype.",
649                 poBand->GetBand(), dfVal,
650                 GDALGetDataTypeName(eBandType));
651     }
652     return dfVal;
653 }
654 
655 /************************************************************************/
656 /*                             GDALTranslate()                          */
657 /************************************************************************/
658 
659 /**
660  * Converts raster data between different formats.
661  *
662  * This is the equivalent of the <a href="/programs/gdal_translate.html">gdal_translate</a> utility.
663  *
664  * GDALTranslateOptions* must be allocated and freed with GDALTranslateOptionsNew()
665  * and GDALTranslateOptionsFree() respectively.
666  *
667  * @param pszDest the destination dataset path.
668  * @param hSrcDataset the source dataset handle.
669  * @param psOptionsIn the options struct returned by GDALTranslateOptionsNew() or NULL.
670  * @param pbUsageError pointer to a integer output variable to store if any usage error has occurred or NULL.
671  * @return the output dataset (new dataset that must be closed using GDALClose()) or NULL in case of error.
672  *
673  * @since GDAL 2.1
674  */
675 
GDALTranslate(const char * pszDest,GDALDatasetH hSrcDataset,const GDALTranslateOptions * psOptionsIn,int * pbUsageError)676 GDALDatasetH GDALTranslate( const char *pszDest, GDALDatasetH hSrcDataset,
677                             const GDALTranslateOptions *psOptionsIn, int *pbUsageError )
678 
679 {
680     CPLErrorReset();
681     if( hSrcDataset == nullptr )
682     {
683         CPLError( CE_Failure, CPLE_AppDefined, "No source dataset specified.");
684 
685         if(pbUsageError)
686             *pbUsageError = TRUE;
687         return nullptr;
688     }
689     if( pszDest == nullptr )
690     {
691         CPLError( CE_Failure, CPLE_AppDefined, "No target dataset specified.");
692 
693         if(pbUsageError)
694             *pbUsageError = TRUE;
695         return nullptr;
696     }
697 
698     GDALTranslateOptions* psOptions =
699         (psOptionsIn) ? GDALTranslateOptionsClone(psOptionsIn) :
700                         GDALTranslateOptionsNew(nullptr, nullptr);
701 
702     GDALDatasetH hOutDS = nullptr;
703     bool bGotBounds = false;
704 
705     if(pbUsageError)
706         *pbUsageError = FALSE;
707 
708     if(psOptions->adfULLR[0] != 0.0 || psOptions->adfULLR[1] != 0.0 || psOptions->adfULLR[2] != 0.0 || psOptions->adfULLR[3] != 0.0)
709         bGotBounds = true;
710 
711     const char *pszSource = GDALGetDescription(hSrcDataset);
712 
713     if( strcmp(pszSource, pszDest) == 0 && pszSource[0] != '\0' &&
714         GDALGetDatasetDriver(hSrcDataset) != GDALGetDriverByName("MEM") )
715     {
716         CPLError( CE_Failure, CPLE_AppDefined, "Source and destination datasets must be different.");
717 
718         if(pbUsageError)
719             *pbUsageError = TRUE;
720         GDALTranslateOptionsFree(psOptions);
721         return nullptr;
722     }
723 
724     CPLString osProjSRS;
725 
726     if(psOptions->pszProjSRS != nullptr)
727     {
728         OGRSpatialReference oSRS;
729         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
730 
731         if( oSRS.SetFromUserInput( psOptions->pszProjSRS ) != OGRERR_NONE )
732         {
733             CPLError( CE_Failure, CPLE_AppDefined, "Failed to process SRS definition: %s",
734                       psOptions->pszProjSRS );
735             GDALTranslateOptionsFree(psOptions);
736             return nullptr;
737         }
738 
739         char* pszSRS = nullptr;
740         oSRS.exportToWkt( &pszSRS );
741         if( pszSRS )
742             osProjSRS = pszSRS;
743         CPLFree( pszSRS );
744     }
745 
746     if(psOptions->pszOutputSRS != nullptr)
747     {
748         OGRSpatialReference oOutputSRS;
749         oOutputSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
750 
751         if( oOutputSRS.SetFromUserInput( psOptions->pszOutputSRS ) != OGRERR_NONE )
752         {
753             CPLError( CE_Failure, CPLE_AppDefined, "Failed to process SRS definition: %s",
754                       psOptions->pszOutputSRS );
755             GDALTranslateOptionsFree(psOptions);
756             return nullptr;
757         }
758 
759         char* pszSRS = nullptr;
760         {
761             CPLErrorStateBackuper oErrorStateBackuper;
762             CPLErrorHandlerPusher oErrorHandler(CPLQuietErrorHandler);
763             if( oOutputSRS.exportToWkt( &pszSRS ) != OGRERR_NONE )
764             {
765                 CPLFree(pszSRS);
766                 pszSRS = nullptr;
767                 const char* const apszOptions[] = { "FORMAT=WKT2", nullptr };
768                 oOutputSRS.exportToWkt( &pszSRS, apszOptions );
769             }
770         }
771         CPLFree( psOptions->pszOutputSRS );
772         psOptions->pszOutputSRS = CPLStrdup( pszSRS );
773         CPLFree( pszSRS );
774     }
775 
776 /* -------------------------------------------------------------------- */
777 /*      Check that incompatible options are not used                    */
778 /* -------------------------------------------------------------------- */
779 
780     if( (psOptions->nOXSizePixel != 0 || psOptions->dfOXSizePct != 0.0 || psOptions->nOYSizePixel != 0 ||
781          psOptions->dfOYSizePct != 0.0) && (psOptions->dfXRes != 0 && psOptions->dfYRes != 0) )
782     {
783         CPLError( CE_Failure, CPLE_IllegalArg, "-outsize and -tr options cannot be used at the same time.");
784         if(pbUsageError)
785             *pbUsageError = TRUE;
786         GDALTranslateOptionsFree(psOptions);
787         return nullptr;
788     }
789     if( bGotBounds &&  (psOptions->dfXRes != 0 && psOptions->dfYRes != 0) )
790     {
791         CPLError( CE_Failure, CPLE_IllegalArg, "-a_ullr and -tr options cannot be used at the same time.");
792         if(pbUsageError)
793             *pbUsageError = TRUE;
794         GDALTranslateOptionsFree(psOptions);
795         return nullptr;
796     }
797 
798 /* -------------------------------------------------------------------- */
799 /*      Collect some information from the source file.                  */
800 /* -------------------------------------------------------------------- */
801     const int nRasterXSize = GDALGetRasterXSize( hSrcDataset );
802     const int nRasterYSize = GDALGetRasterYSize( hSrcDataset );
803 
804     if( psOptions->adfSrcWin[2] == 0 && psOptions->adfSrcWin[3] == 0 )
805     {
806         psOptions->adfSrcWin[2] = nRasterXSize;
807         psOptions->adfSrcWin[3] = nRasterYSize;
808     }
809 
810 /* -------------------------------------------------------------------- */
811 /*      Build band list to translate                                    */
812 /* -------------------------------------------------------------------- */
813     bool bAllBandsInOrder = true;
814 
815     if( psOptions->panBandList == nullptr )
816     {
817 
818         psOptions->nBandCount = GDALGetRasterCount( hSrcDataset );
819         if( ( psOptions->nBandCount == 0 ) && (psOptions->bStrict ) )
820         {
821             // if not strict then the driver can fail if it doesn't support zero bands
822             CPLError( CE_Failure, CPLE_AppDefined, "Input file has no bands, and so cannot be translated." );
823             GDALTranslateOptionsFree(psOptions);
824             return nullptr;
825         }
826 
827         psOptions->panBandList = static_cast<int *>(
828             CPLMalloc(sizeof(int) * psOptions->nBandCount));
829         for( int i = 0; i < psOptions->nBandCount; i++ )
830             psOptions->panBandList[i] = i+1;
831     }
832     else
833     {
834         for( int i = 0; i < psOptions->nBandCount; i++ )
835         {
836             if( std::abs(psOptions->panBandList[i]) >
837                 GDALGetRasterCount(hSrcDataset) )
838             {
839                 CPLError(CE_Failure, CPLE_AppDefined,
840                          "Band %d requested, but only bands 1 to %d available.",
841                          std::abs(psOptions->panBandList[i]),
842                          GDALGetRasterCount(hSrcDataset) );
843                 GDALTranslateOptionsFree(psOptions);
844                 return nullptr;
845             }
846 
847             if( psOptions->panBandList[i] != i+1 )
848                 bAllBandsInOrder = FALSE;
849         }
850 
851         if( psOptions->nBandCount != GDALGetRasterCount( hSrcDataset ) )
852             bAllBandsInOrder = FALSE;
853     }
854 
855     if( psOptions->nScaleRepeat > psOptions->nBandCount )
856     {
857         if( !psOptions->bHasUsedExplicitScaleBand )
858             CPLError( CE_Failure, CPLE_IllegalArg, "-scale has been specified more times than the number of output bands");
859         else
860             CPLError( CE_Failure, CPLE_IllegalArg, "-scale_XX has been specified with XX greater than the number of output bands");
861         if(pbUsageError)
862             *pbUsageError = TRUE;
863         GDALTranslateOptionsFree(psOptions);
864         return nullptr;
865     }
866 
867     if( psOptions->nExponentRepeat > psOptions->nBandCount )
868     {
869         if( !psOptions->bHasUsedExplicitExponentBand )
870             CPLError( CE_Failure, CPLE_IllegalArg, "-exponent has been specified more times than the number of output bands");
871         else
872             CPLError( CE_Failure, CPLE_IllegalArg, "-exponent_XX has been specified with XX greater than the number of output bands");
873         if(pbUsageError)
874             *pbUsageError = TRUE;
875         GDALTranslateOptionsFree(psOptions);
876         return nullptr;
877     }
878 /* -------------------------------------------------------------------- */
879 /*      Compute the source window from the projected source window      */
880 /*      if the projected coordinates were provided.  Note that the      */
881 /*      projected coordinates are in ulx, uly, lrx, lry format,         */
882 /*      while the adfSrcWin is xoff, yoff, xsize, ysize with the        */
883 /*      xoff,yoff being the ulx, uly in pixel/line.                     */
884 /* -------------------------------------------------------------------- */
885     const char *pszProjection = nullptr;
886 
887     if( psOptions->dfULX != 0.0 || psOptions->dfULY != 0.0
888         || psOptions->dfLRX != 0.0 || psOptions->dfLRY != 0.0 )
889     {
890         double adfGeoTransform[6];
891 
892         GDALGetGeoTransform( hSrcDataset, adfGeoTransform );
893 
894         if( adfGeoTransform[1] == 0.0 || adfGeoTransform[5] == 0.0 )
895         {
896             CPLError( CE_Failure, CPLE_AppDefined,
897                      "The -projwin option was used, but the geotransform is "
898                      "invalid." );
899             GDALTranslateOptionsFree(psOptions);
900             return nullptr;
901         }
902         if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
903         {
904             CPLError( CE_Failure, CPLE_AppDefined,
905                      "The -projwin option was used, but the geotransform is\n"
906                      "rotated.  This configuration is not supported." );
907             GDALTranslateOptionsFree(psOptions);
908             return nullptr;
909         }
910 
911         if( !osProjSRS.empty() )
912         {
913             pszProjection = GDALGetProjectionRef( hSrcDataset );
914             if( pszProjection != nullptr && strlen(pszProjection) > 0 )
915             {
916                 OGRSpatialReference oSRSIn;
917                 OGRSpatialReference oSRSDS;
918                 oSRSIn.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
919                 oSRSDS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
920                 oSRSIn.SetFromUserInput(osProjSRS);
921                 oSRSDS.SetFromUserInput(pszProjection);
922                 if( !oSRSIn.IsSame(&oSRSDS) )
923                 {
924                     OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(&oSRSIn, &oSRSDS);
925                     if( !(poCT &&
926                         poCT->Transform(1, &psOptions->dfULX, &psOptions->dfULY) &&
927                         poCT->Transform(1, &psOptions->dfLRX, &psOptions->dfLRY)) )
928                     {
929                         OGRCoordinateTransformation::DestroyCT(poCT);
930 
931                         CPLError( CE_Failure, CPLE_AppDefined, "-projwin_srs ignored since coordinate transformation failed.");
932                         GDALTranslateOptionsFree(psOptions);
933                         return nullptr;
934                     }
935                     delete poCT;
936                 }
937             }
938             else
939             {
940                 CPLError( CE_None, CPLE_None, "-projwin_srs ignored since the dataset has no projection.");
941             }
942         }
943 
944         psOptions->adfSrcWin[0] = (psOptions->dfULX - adfGeoTransform[0]) / adfGeoTransform[1];
945         psOptions->adfSrcWin[1] = (psOptions->dfULY - adfGeoTransform[3]) / adfGeoTransform[5];
946 
947         psOptions->adfSrcWin[2] = (psOptions->dfLRX - psOptions->dfULX) / adfGeoTransform[1];
948         psOptions->adfSrcWin[3] = (psOptions->dfLRY - psOptions->dfULY) / adfGeoTransform[5];
949 
950         // In case of nearest resampling, round to integer pixels (#6610)
951         if( psOptions->pszResampling == nullptr ||
952             EQUALN(psOptions->pszResampling, "NEAR", 4) )
953         {
954             psOptions->adfSrcWin[0] = floor(psOptions->adfSrcWin[0] + 0.001);
955             psOptions->adfSrcWin[1] = floor(psOptions->adfSrcWin[1] + 0.001);
956             psOptions->adfSrcWin[2] = floor(psOptions->adfSrcWin[2] + 0.5);
957             psOptions->adfSrcWin[3] = floor(psOptions->adfSrcWin[3] + 0.5);
958         }
959 
960         /*if( !bQuiet )
961             fprintf( stdout,
962                      "Computed -srcwin %g %g %g %g from projected window.\n",
963                      adfSrcWin[0],
964                      adfSrcWin[1],
965                      adfSrcWin[2],
966                      adfSrcWin[3] ); */
967     }
968 
969 /* -------------------------------------------------------------------- */
970 /*      Verify source window dimensions.                                */
971 /* -------------------------------------------------------------------- */
972     if( psOptions->adfSrcWin[2] <= 0 || psOptions->adfSrcWin[3] <= 0 )
973     {
974         CPLError( CE_Failure, CPLE_AppDefined,
975                  "Error: %s-srcwin %g %g %g %g has negative width and/or height.",
976                  ( psOptions->dfULX != 0.0 || psOptions->dfULY != 0.0 || psOptions->dfLRX != 0.0 || psOptions->dfLRY != 0.0 ) ? "Computed " : "",
977                  psOptions->adfSrcWin[0],
978                  psOptions->adfSrcWin[1],
979                  psOptions->adfSrcWin[2],
980                  psOptions->adfSrcWin[3] );
981         GDALTranslateOptionsFree(psOptions);
982         return nullptr;
983     }
984 
985 /* -------------------------------------------------------------------- */
986 /*      Verify source window dimensions.                                */
987 /* -------------------------------------------------------------------- */
988     else if( psOptions->adfSrcWin[0] <= -1 || psOptions->adfSrcWin[1] <= -1
989         || psOptions->adfSrcWin[0] + psOptions->adfSrcWin[2] >= GDALGetRasterXSize(hSrcDataset) + 1
990         || psOptions->adfSrcWin[1] + psOptions->adfSrcWin[3] >= GDALGetRasterYSize(hSrcDataset) + 1 )
991     {
992         const bool bCompletelyOutside =
993             psOptions->adfSrcWin[0] + psOptions->adfSrcWin[2] <= 0 ||
994             psOptions->adfSrcWin[1] + psOptions->adfSrcWin[3] <= 0 ||
995             psOptions->adfSrcWin[0] >= GDALGetRasterXSize(hSrcDataset) ||
996             psOptions->adfSrcWin[1] >= GDALGetRasterYSize(hSrcDataset);
997         const bool bIsError =
998             psOptions->bErrorOnPartiallyOutside ||
999             (bCompletelyOutside && psOptions->bErrorOnCompletelyOutside);
1000         if( !psOptions->bQuiet || bIsError )
1001         {
1002             CPLErr eErr = bIsError ? CE_Failure : CE_Warning;
1003 
1004             CPLError( eErr, CPLE_AppDefined,
1005                  "%s-srcwin %g %g %g %g falls %s outside raster extent.%s",
1006                  ( psOptions->dfULX != 0.0 || psOptions->dfULY != 0.0 || psOptions->dfLRX != 0.0 || psOptions->dfLRY != 0.0 ) ? "Computed " : "",
1007                  psOptions->adfSrcWin[0],
1008                  psOptions->adfSrcWin[1],
1009                  psOptions->adfSrcWin[2],
1010                  psOptions->adfSrcWin[3],
1011                  bCompletelyOutside ? "completely" : "partially",
1012                  bIsError ? "" : " Going on however." );
1013         }
1014         if( bIsError )
1015         {
1016             GDALTranslateOptionsFree(psOptions);
1017             return nullptr;
1018         }
1019     }
1020 
1021 /* -------------------------------------------------------------------- */
1022 /*      Find the output driver.                                         */
1023 /* -------------------------------------------------------------------- */
1024     if( psOptions->pszFormat == nullptr )
1025     {
1026         CPLString osFormat = GetOutputDriverForRaster(pszDest);
1027         if( osFormat.empty() )
1028         {
1029             GDALTranslateOptionsFree(psOptions);
1030             return nullptr;
1031         }
1032         psOptions->pszFormat = CPLStrdup(osFormat);
1033     }
1034 
1035     GDALDriverH hDriver = GDALGetDriverByName(psOptions->pszFormat);
1036     if( hDriver == nullptr )
1037     {
1038         CPLError( CE_Failure, CPLE_IllegalArg, "Output driver `%s' not recognised.",
1039                   psOptions->pszFormat);
1040         GDALTranslateOptionsFree(psOptions);
1041         return nullptr;
1042     }
1043 
1044 /* -------------------------------------------------------------------- */
1045 /*      Make sure we cleanup if there is an existing dataset of this    */
1046 /*      name.  But even if that seems to fail we will continue since    */
1047 /*      it might just be a corrupt file or something.                   */
1048 /*      This is needed for                                              */
1049 /*      gdal_translate foo.tif foo.tif.ovr -outsize 50% 50%             */
1050 /* -------------------------------------------------------------------- */
1051     if( !CPLFetchBool(psOptions->papszCreateOptions, "APPEND_SUBDATASET", false) )
1052     {
1053         // Someone issuing Create("foo.tif") on a
1054         // memory driver doesn't expect files with those names to be deleted
1055         // on a file system...
1056         // This is somewhat messy. Ideally there should be a way for the
1057         // driver to overload the default behavior
1058         if( !EQUAL(psOptions->pszFormat, "MEM") &&
1059             !EQUAL(psOptions->pszFormat, "Memory") )
1060         {
1061             GDALDriver::FromHandle(hDriver)->QuietDelete( pszDest );
1062         }
1063         // Make sure to load early overviews, so that on the GTiff driver
1064         // external .ovr is looked for before it might be created as the
1065         // output dataset !
1066         if( GDALGetRasterCount( hSrcDataset ) )
1067         {
1068             auto hBand = GDALGetRasterBand(hSrcDataset, 1);
1069             if( hBand )
1070                 GDALGetOverviewCount(hBand);
1071         }
1072     }
1073 
1074     char** papszDriverMD = GDALGetMetadata(hDriver, nullptr);
1075 
1076     if( !CPLTestBool( CSLFetchNameValueDef(papszDriverMD,
1077                                            GDAL_DCAP_RASTER, "FALSE") ) )
1078     {
1079         CPLError( CE_Failure, CPLE_AppDefined,
1080                   "%s driver has no raster capabilities.",
1081                   psOptions->pszFormat );
1082         GDALTranslateOptionsFree(psOptions);
1083         return nullptr;
1084     }
1085 
1086     if( !CPLTestBool( CSLFetchNameValueDef(papszDriverMD,
1087                                           GDAL_DCAP_CREATE, "FALSE") ) &&
1088         !CPLTestBool( CSLFetchNameValueDef(papszDriverMD,
1089                                           GDAL_DCAP_CREATECOPY, "FALSE") ))
1090     {
1091         CPLError( CE_Failure, CPLE_AppDefined,
1092                   "%s driver has no creation capabilities.",
1093                   psOptions->pszFormat );
1094         GDALTranslateOptionsFree(psOptions);
1095         return nullptr;
1096     }
1097 
1098 /* -------------------------------------------------------------------- */
1099 /*      The short form is to CreateCopy().  We use this if the input    */
1100 /*      matches the whole dataset.  Eventually we should rewrite        */
1101 /*      this entire program to use virtual datasets to construct a      */
1102 /*      virtual input source to copy from.                              */
1103 /* -------------------------------------------------------------------- */
1104 
1105     const bool bSpatialArrangementPreserved =
1106         psOptions->adfSrcWin[0] == 0 && psOptions->adfSrcWin[1] == 0 &&
1107         psOptions->adfSrcWin[2] == GDALGetRasterXSize(hSrcDataset) &&
1108         psOptions->adfSrcWin[3] == GDALGetRasterYSize(hSrcDataset) &&
1109         psOptions->nOXSizePixel == 0 && psOptions->dfOXSizePct == 0.0 &&
1110         psOptions->nOYSizePixel == 0 && psOptions->dfOYSizePct == 0.0 &&
1111         psOptions->dfXRes == 0.0;
1112 
1113     if( psOptions->eOutputType == GDT_Unknown
1114         && psOptions->nScaleRepeat == 0 && psOptions->nExponentRepeat == 0 && !psOptions->bUnscale
1115         && !psOptions->bSetScale && !psOptions->bSetOffset
1116         && CSLCount(psOptions->papszMetadataOptions) == 0 && bAllBandsInOrder
1117         && psOptions->eMaskMode == MASK_AUTO
1118         && bSpatialArrangementPreserved
1119         && !psOptions->bNoGCP
1120         && psOptions->nGCPCount == 0 && !bGotBounds
1121         && psOptions->pszOutputSRS == nullptr && !psOptions->bSetNoData && !psOptions->bUnsetNoData
1122         && psOptions->nRGBExpand == 0 && !psOptions->bNoRAT
1123         && psOptions->panColorInterp == nullptr
1124         && !psOptions->bNoXMP )
1125     {
1126 
1127         // For gdal_translate_fuzzer
1128         if( psOptions->nLimitOutSize > 0 )
1129         {
1130             vsi_l_offset nRawOutSize =
1131                static_cast<vsi_l_offset>(GDALGetRasterXSize(hSrcDataset)) *
1132                 GDALGetRasterYSize(hSrcDataset) *
1133                 psOptions->nBandCount;
1134             if( psOptions->nBandCount )
1135             {
1136                 nRawOutSize *= GDALGetDataTypeSizeBytes(
1137                     static_cast<GDALDataset *>(hSrcDataset)->GetRasterBand(1)->GetRasterDataType() );
1138             }
1139             if( nRawOutSize > static_cast<vsi_l_offset>(psOptions->nLimitOutSize) )
1140             {
1141                 CPLError( CE_Failure, CPLE_IllegalArg,
1142                           "Attempt to create %dx%d dataset is above authorized limit.",
1143                           GDALGetRasterXSize(hSrcDataset),
1144                           GDALGetRasterYSize(hSrcDataset) );
1145                 GDALTranslateOptionsFree(psOptions);
1146                 return nullptr;
1147             }
1148         }
1149 
1150 /* -------------------------------------------------------------------- */
1151 /*      Compute stats if required.                                      */
1152 /* -------------------------------------------------------------------- */
1153         if (psOptions->bStats)
1154         {
1155             GDALDataset* poSrcDS = GDALDataset::FromHandle(hSrcDataset);
1156             for( int i = 0; i < poSrcDS->GetRasterCount(); i++ )
1157             {
1158                 double dfMin, dfMax, dfMean, dfStdDev;
1159                 poSrcDS->GetRasterBand(i+1)->ComputeStatistics(
1160                     psOptions->bApproxStats,
1161                     &dfMin, &dfMax, &dfMean, &dfStdDev,
1162                     GDALDummyProgress, nullptr );
1163             }
1164         }
1165 
1166         hOutDS = GDALCreateCopy( hDriver, pszDest, hSrcDataset,
1167                                  psOptions->bStrict, psOptions->papszCreateOptions,
1168                                  psOptions->pfnProgress, psOptions->pProgressData );
1169         hOutDS = GDALTranslateFlush(hOutDS);
1170 
1171         GDALTranslateOptionsFree(psOptions);
1172         return hOutDS;
1173     }
1174 
1175     if( CSLFetchNameValue(psOptions->papszCreateOptions, "COPY_SRC_OVERVIEWS") )
1176     {
1177         CPLError(CE_Warning, CPLE_AppDefined,
1178                  "General options of gdal_translate make the "
1179                  "COPY_SRC_OVERVIEWS creation option ineffective as they hide "
1180                  "the overviews");
1181     }
1182 
1183 /* -------------------------------------------------------------------- */
1184 /*      Establish some parameters.                                      */
1185 /* -------------------------------------------------------------------- */
1186     int nOXSize = 0;
1187     int nOYSize = 0;
1188 
1189     bool bHasSrcGeoTransform = false;
1190     double adfSrcGeoTransform[6] = {};
1191     if( GDALGetGeoTransform( hSrcDataset, adfSrcGeoTransform ) == CE_None )
1192         bHasSrcGeoTransform = true;
1193 
1194     if( psOptions->dfXRes != 0.0 )
1195     {
1196         if( !(bHasSrcGeoTransform &&
1197               psOptions->nGCPCount == 0 &&
1198               adfSrcGeoTransform[2] == 0.0 && adfSrcGeoTransform[4] == 0.0) )
1199         {
1200             CPLError( CE_Failure, CPLE_IllegalArg,
1201                      "The -tr option was used, but there's no geotransform or it is\n"
1202                      "rotated.  This configuration is not supported." );
1203             GDALTranslateOptionsFree(psOptions);
1204             return nullptr;
1205         }
1206         const double dfOXSize =
1207             psOptions->adfSrcWin[2] /
1208             psOptions->dfXRes * adfSrcGeoTransform[1] + 0.5;
1209         const double dfOYSize =
1210             psOptions->adfSrcWin[3] /
1211             psOptions->dfYRes * fabs(adfSrcGeoTransform[5]) + 0.5;
1212         if( dfOXSize < 1 || !GDALIsValueInRange<int>(dfOXSize) ||
1213             dfOYSize < 1 || !GDALIsValueInRange<int>(dfOXSize) )
1214         {
1215             CPLError(CE_Failure, CPLE_IllegalArg,
1216                      "Invalid output size: %g x %g",
1217                      dfOXSize, dfOYSize);
1218             GDALTranslateOptionsFree(psOptions);
1219             return nullptr;
1220         }
1221         nOXSize = static_cast<int>(dfOXSize);
1222         nOYSize = static_cast<int>(dfOYSize);
1223     }
1224     else if( psOptions->nOXSizePixel == 0 && psOptions->dfOXSizePct == 0.0 && psOptions->nOYSizePixel == 0 && psOptions->dfOYSizePct == 0.0)
1225     {
1226         double dfOXSize = ceil(psOptions->adfSrcWin[2]-0.001);
1227         double dfOYSize = ceil(psOptions->adfSrcWin[3]-0.001);
1228         if( dfOXSize < 1 || !GDALIsValueInRange<int>(dfOXSize) ||
1229             dfOYSize < 1 || !GDALIsValueInRange<int>(dfOXSize) )
1230         {
1231             CPLError(CE_Failure, CPLE_IllegalArg,
1232                      "Invalid output size: %g x %g",
1233                      dfOXSize, dfOYSize);
1234             GDALTranslateOptionsFree(psOptions);
1235             return nullptr;
1236         }
1237         nOXSize = static_cast<int>(dfOXSize);
1238         nOYSize = static_cast<int>(dfOYSize);
1239     }
1240     else
1241     {
1242         if( !(psOptions->nOXSizePixel == 0 && psOptions->dfOXSizePct == 0.0) )
1243         {
1244             if(psOptions->nOXSizePixel != 0)
1245                 nOXSize = psOptions->nOXSizePixel;
1246             else
1247             {
1248                 const double dfOXSize =
1249                     psOptions->dfOXSizePct / 100 * psOptions->adfSrcWin[2];
1250                 if( dfOXSize < 1 || !GDALIsValueInRange<int>(dfOXSize) )
1251                 {
1252                     CPLError(CE_Failure, CPLE_IllegalArg,
1253                             "Invalid output width: %g",
1254                             dfOXSize);
1255                     GDALTranslateOptionsFree(psOptions);
1256                     return nullptr;
1257                 }
1258                 nOXSize = static_cast<int>(dfOXSize);
1259             }
1260         }
1261 
1262         if( !(psOptions->nOYSizePixel == 0 && psOptions->dfOYSizePct == 0.0) )
1263         {
1264             if(psOptions->nOYSizePixel != 0)
1265                 nOYSize = psOptions->nOYSizePixel;
1266             else
1267             {
1268                 const double dfOYSize =
1269                     psOptions->dfOYSizePct / 100 * psOptions->adfSrcWin[3];
1270                 if( dfOYSize < 1 || !GDALIsValueInRange<int>(dfOYSize) )
1271                 {
1272                     CPLError(CE_Failure, CPLE_IllegalArg,
1273                             "Invalid output height: %g",
1274                             dfOYSize);
1275                     GDALTranslateOptionsFree(psOptions);
1276                     return nullptr;
1277                 }
1278                 nOYSize = static_cast<int>(dfOYSize);
1279             }
1280         }
1281 
1282         if( psOptions->nOXSizePixel == 0 && psOptions->dfOXSizePct == 0.0 )
1283         {
1284             const double dfOXSize =
1285                 static_cast<double>(nOYSize) * psOptions->adfSrcWin[2] /
1286                 psOptions->adfSrcWin[3] + 0.5;
1287             if( dfOXSize < 1 || !GDALIsValueInRange<int>(dfOXSize) )
1288             {
1289                 CPLError(CE_Failure, CPLE_IllegalArg,
1290                         "Invalid output width: %g",
1291                         dfOXSize);
1292                 GDALTranslateOptionsFree(psOptions);
1293                 return nullptr;
1294             }
1295             nOXSize = static_cast<int>(dfOXSize);
1296         }
1297         else if( psOptions->nOYSizePixel == 0 && psOptions->dfOYSizePct == 0.0 )
1298         {
1299             const double dfOYSize =
1300                 static_cast<double>(nOXSize) * psOptions->adfSrcWin[3] /
1301                 psOptions->adfSrcWin[2] + 0.5;
1302             if( dfOYSize < 1 || !GDALIsValueInRange<int>(dfOYSize) )
1303             {
1304                 CPLError(CE_Failure, CPLE_IllegalArg,
1305                         "Invalid output height: %g",
1306                         dfOYSize);
1307                 GDALTranslateOptionsFree(psOptions);
1308                 return nullptr;
1309             }
1310             nOYSize = static_cast<int>(dfOYSize);
1311         }
1312     }
1313 
1314     if( nOXSize <= 0 || nOYSize <= 0 )
1315     {
1316         CPLError( CE_Failure, CPLE_IllegalArg, "Attempt to create %dx%d dataset is illegal.", nOXSize, nOYSize);
1317         GDALTranslateOptionsFree(psOptions);
1318         return nullptr;
1319     }
1320 
1321     // For gdal_translate_fuzzer
1322     if( psOptions->nLimitOutSize > 0 )
1323     {
1324         vsi_l_offset nRawOutSize = static_cast<vsi_l_offset>(nOXSize) * nOYSize;
1325         if( psOptions->nBandCount )
1326         {
1327             if( nRawOutSize > std::numeric_limits<vsi_l_offset>::max() / psOptions->nBandCount )
1328             {
1329                 GDALTranslateOptionsFree(psOptions);
1330                 return nullptr;
1331             }
1332             nRawOutSize *= psOptions->nBandCount;
1333             const int nDTSize = GDALGetDataTypeSizeBytes(
1334                 static_cast<GDALDataset *>(hSrcDataset)->GetRasterBand(1)->GetRasterDataType() );
1335             if( nDTSize > 0 &&
1336                 nRawOutSize > std::numeric_limits<vsi_l_offset>::max() / nDTSize )
1337             {
1338                 GDALTranslateOptionsFree(psOptions);
1339                 return nullptr;
1340             }
1341             nRawOutSize *= nDTSize;
1342         }
1343         if( nRawOutSize > static_cast<vsi_l_offset>(psOptions->nLimitOutSize) )
1344         {
1345             CPLError( CE_Failure, CPLE_IllegalArg,
1346                       "Attempt to create %dx%d dataset is above authorized limit.",
1347                       nOXSize, nOYSize);
1348             GDALTranslateOptionsFree(psOptions);
1349             return nullptr;
1350         }
1351     }
1352 
1353 
1354 /* ==================================================================== */
1355 /*      Create a virtual dataset.                                       */
1356 /* ==================================================================== */
1357 
1358 /* -------------------------------------------------------------------- */
1359 /*      Make a virtual clone.                                           */
1360 /* -------------------------------------------------------------------- */
1361     VRTDataset *poVDS = static_cast<VRTDataset *>(VRTCreate(nOXSize, nOYSize));
1362 
1363     if( psOptions->nGCPCount == 0 )
1364     {
1365         if( psOptions->pszOutputSRS != nullptr )
1366         {
1367             poVDS->SetProjection( psOptions->pszOutputSRS );
1368         }
1369         else
1370         {
1371             pszProjection = GDALGetProjectionRef( hSrcDataset );
1372             if( pszProjection != nullptr && strlen(pszProjection) > 0 )
1373                 poVDS->SetProjection( pszProjection );
1374         }
1375     }
1376 
1377     bool bHasDstGeoTransform = false;
1378     double adfDstGeoTransform[6] = {};
1379 
1380     if( bGotBounds )
1381     {
1382         bHasDstGeoTransform = true;
1383         adfDstGeoTransform[0] = psOptions->adfULLR[0];
1384         adfDstGeoTransform[1] = (psOptions->adfULLR[2] - psOptions->adfULLR[0]) / nOXSize;
1385         adfDstGeoTransform[2] = 0.0;
1386         adfDstGeoTransform[3] = psOptions->adfULLR[1];
1387         adfDstGeoTransform[4] = 0.0;
1388         adfDstGeoTransform[5] = (psOptions->adfULLR[3] - psOptions->adfULLR[1]) / nOYSize;
1389 
1390         poVDS->SetGeoTransform( adfDstGeoTransform );
1391     }
1392 
1393     else if( bHasSrcGeoTransform && psOptions->nGCPCount == 0 )
1394     {
1395         bHasDstGeoTransform = true;
1396         memcpy( adfDstGeoTransform, adfSrcGeoTransform, 6 * sizeof(double) );
1397         adfDstGeoTransform[0] += psOptions->adfSrcWin[0] * adfDstGeoTransform[1]
1398             + psOptions->adfSrcWin[1] * adfDstGeoTransform[2];
1399         adfDstGeoTransform[3] += psOptions->adfSrcWin[0] * adfDstGeoTransform[4]
1400             + psOptions->adfSrcWin[1] * adfDstGeoTransform[5];
1401 
1402         const double dfX = static_cast<double>(nOXSize);
1403         const double dfY = static_cast<double>(nOYSize);
1404         adfDstGeoTransform[1] *= psOptions->adfSrcWin[2] / dfX;
1405         adfDstGeoTransform[2] *= psOptions->adfSrcWin[3] / dfY;
1406         adfDstGeoTransform[4] *= psOptions->adfSrcWin[2] / dfX;
1407         adfDstGeoTransform[5] *= psOptions->adfSrcWin[3] / dfY;
1408 
1409         if( psOptions->dfXRes != 0.0 )
1410         {
1411             adfDstGeoTransform[1] = psOptions->dfXRes;
1412             adfDstGeoTransform[5] = (adfDstGeoTransform[5] > 0) ? psOptions->dfYRes : -psOptions->dfYRes;
1413         }
1414 
1415         poVDS->SetGeoTransform( adfDstGeoTransform );
1416     }
1417 
1418     if( psOptions->nGCPCount != 0 )
1419     {
1420         const char *pszGCPProjection = psOptions->pszOutputSRS;
1421 
1422         if( pszGCPProjection == nullptr )
1423             pszGCPProjection = GDALGetGCPProjection( hSrcDataset );
1424         if( pszGCPProjection == nullptr )
1425             pszGCPProjection = "";
1426 
1427         poVDS->SetGCPs( psOptions->nGCPCount, psOptions->pasGCPs, pszGCPProjection );
1428     }
1429 
1430     else if( !psOptions->bNoGCP && GDALGetGCPCount( hSrcDataset ) > 0 )
1431     {
1432         const int nGCPs = GDALGetGCPCount(hSrcDataset);
1433 
1434         GDAL_GCP *pasGCPs = GDALDuplicateGCPs(nGCPs, GDALGetGCPs(hSrcDataset));
1435 
1436         for( int i = 0; i < nGCPs; i++ )
1437         {
1438             pasGCPs[i].dfGCPPixel -= psOptions->adfSrcWin[0];
1439             pasGCPs[i].dfGCPLine  -= psOptions->adfSrcWin[1];
1440             pasGCPs[i].dfGCPPixel *=
1441                 nOXSize / static_cast<double>(psOptions->adfSrcWin[2]);
1442             pasGCPs[i].dfGCPLine  *=
1443                 nOYSize / static_cast<double>(psOptions->adfSrcWin[3]);
1444         }
1445 
1446         poVDS->SetGCPs( nGCPs, pasGCPs,
1447                         GDALGetGCPProjection( hSrcDataset ) );
1448 
1449         GDALDeinitGCPs( nGCPs, pasGCPs );
1450         CPLFree( pasGCPs );
1451     }
1452 
1453 /* -------------------------------------------------------------------- */
1454 /*      To make the VRT to look less awkward (but this is optional      */
1455 /*      in fact), avoid negative values.                                */
1456 /* -------------------------------------------------------------------- */
1457     double adfDstWin[4] =
1458         {0.0, 0.0, static_cast<double>(nOXSize), static_cast<double>(nOYSize)};
1459 
1460     // When specifying -tr with non-nearest resampling, make sure that the
1461     // size of target window precisely matches the requested resolution, to
1462     // avoid any shift.
1463     if( bHasSrcGeoTransform && bHasDstGeoTransform &&
1464         psOptions->dfXRes != 0.0 &&
1465         psOptions->pszResampling != nullptr &&
1466         !EQUALN(psOptions->pszResampling, "NEAR", 4) )
1467     {
1468         adfDstWin[2] = psOptions->adfSrcWin[2] * adfSrcGeoTransform[1] / adfDstGeoTransform[1];
1469         adfDstWin[3] = psOptions->adfSrcWin[3] * fabs(adfSrcGeoTransform[5] / adfDstGeoTransform[5]);
1470     }
1471 
1472     double adfSrcWinOri[4];
1473     static_assert(sizeof(adfSrcWinOri) == sizeof(psOptions->adfSrcWin),
1474                   "inconsistent adfSrcWin size");
1475     memcpy(adfSrcWinOri, psOptions->adfSrcWin, sizeof(psOptions->adfSrcWin));
1476     FixSrcDstWindow( psOptions->adfSrcWin, adfDstWin,
1477                      GDALGetRasterXSize(hSrcDataset),
1478                      GDALGetRasterYSize(hSrcDataset) );
1479 
1480 /* -------------------------------------------------------------------- */
1481 /*      Transfer generally applicable metadata.                         */
1482 /* -------------------------------------------------------------------- */
1483     GDALDataset* poSrcDS = GDALDataset::FromHandle(hSrcDataset);
1484     char** papszMetadata = CSLDuplicate(poSrcDS->GetMetadata());
1485     if ( psOptions->nScaleRepeat > 0 || psOptions->bUnscale || psOptions->eOutputType != GDT_Unknown )
1486     {
1487         /* Remove TIFFTAG_MINSAMPLEVALUE and TIFFTAG_MAXSAMPLEVALUE */
1488         /* if the data range may change because of options */
1489         char** papszIter = papszMetadata;
1490         while(papszIter && *papszIter)
1491         {
1492             if (STARTS_WITH_CI(*papszIter, "TIFFTAG_MINSAMPLEVALUE=") ||
1493                 STARTS_WITH_CI(*papszIter, "TIFFTAG_MAXSAMPLEVALUE="))
1494             {
1495                 CPLFree(*papszIter);
1496                 memmove(papszIter, papszIter+1, sizeof(char*) * (CSLCount(papszIter+1)+1));
1497             }
1498             else
1499                 papszIter++;
1500         }
1501     }
1502 
1503     // Remove NITF_BLOCKA_ stuff if georeferencing is changed
1504     if( !(psOptions->adfSrcWin[0] == 0 && psOptions->adfSrcWin[1] == 0 &&
1505           psOptions->adfSrcWin[2] == GDALGetRasterXSize(hSrcDataset) &&
1506           psOptions->adfSrcWin[3] == GDALGetRasterYSize(hSrcDataset) &&
1507           psOptions->nGCPCount == 0 && !bGotBounds) )
1508     {
1509         char** papszIter = papszMetadata;
1510         while(papszIter && *papszIter)
1511         {
1512             if (STARTS_WITH_CI(*papszIter, "NITF_BLOCKA_"))
1513             {
1514                 CPLFree(*papszIter);
1515                 memmove(papszIter, papszIter+1, sizeof(char*) * (CSLCount(papszIter+1)+1));
1516             }
1517             else
1518                 papszIter++;
1519         }
1520     }
1521 
1522     {
1523         char** papszIter = papszMetadata;
1524         while(papszIter && *papszIter)
1525         {
1526             // Do not preserve the CACHE_PATH from the WMS driver
1527             if (STARTS_WITH_CI(*papszIter, "CACHE_PATH="))
1528             {
1529                 CPLFree(*papszIter);
1530                 memmove(papszIter, papszIter+1, sizeof(char*) * (CSLCount(papszIter+1)+1));
1531             }
1532             else
1533                 papszIter++;
1534         }
1535     }
1536 
1537     poVDS->SetMetadata( papszMetadata );
1538     CSLDestroy( papszMetadata );
1539     AttachMetadata( static_cast<GDALDatasetH>(poVDS), psOptions->papszMetadataOptions );
1540 
1541     const char* pszInterleave = GDALGetMetadataItem(hSrcDataset, "INTERLEAVE", "IMAGE_STRUCTURE");
1542     if (pszInterleave)
1543         poVDS->SetMetadataItem("INTERLEAVE", pszInterleave, "IMAGE_STRUCTURE");
1544 
1545     {
1546         const char* pszCompression = poSrcDS->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE");
1547         if( pszCompression )
1548         {
1549             poVDS->SetMetadataItem("COMPRESSION", pszCompression, "IMAGE_STRUCTURE");
1550         }
1551     }
1552 
1553     /* ISIS3 metadata preservation */
1554     char** papszMD_ISIS3 = poSrcDS->GetMetadata("json:ISIS3");
1555     if( papszMD_ISIS3 != nullptr)
1556     {
1557         if( !bAllBandsInOrder )
1558         {
1559             CPLString osJSON = EditISIS3MetadataForBandChange(
1560                 papszMD_ISIS3[0], GDALGetRasterCount( hSrcDataset ), psOptions);
1561             if( !osJSON.empty() )
1562             {
1563                 char* apszMD[] = { &osJSON[0], nullptr };
1564                 poVDS->SetMetadata( apszMD, "json:ISIS3" );
1565             }
1566         }
1567         else
1568         {
1569             poVDS->SetMetadata( papszMD_ISIS3, "json:ISIS3" );
1570         }
1571     }
1572 
1573     // PDS4 -> PDS4 special case
1574     if( EQUAL(psOptions->pszFormat, "PDS4") )
1575     {
1576         char** papszMD_PDS4 = poSrcDS->GetMetadata("xml:PDS4");
1577         if( papszMD_PDS4 != nullptr)
1578             poVDS->SetMetadata( papszMD_PDS4, "xml:PDS4" );
1579     }
1580 
1581     // VICAR -> VICAR special case
1582     if( EQUAL(psOptions->pszFormat, "VICAR") )
1583     {
1584         char** papszMD_VICAR = poSrcDS->GetMetadata("json:VICAR");
1585         if( papszMD_VICAR != nullptr)
1586             poVDS->SetMetadata( papszMD_VICAR, "json:VICAR" );
1587     }
1588 
1589     // Copy XMP metadata
1590     if( !psOptions->bNoXMP )
1591     {
1592         char** papszXMP = poSrcDS->GetMetadata("xml:XMP");
1593         if (papszXMP != nullptr && *papszXMP != nullptr)
1594         {
1595             poVDS->SetMetadata(papszXMP, "xml:XMP");
1596         }
1597     }
1598 
1599 
1600 /* -------------------------------------------------------------------- */
1601 /*      Transfer metadata that remains valid if the spatial             */
1602 /*      arrangement of the data is unaltered.                           */
1603 /* -------------------------------------------------------------------- */
1604     if( bSpatialArrangementPreserved )
1605     {
1606         char **papszMD = poSrcDS->GetMetadata("RPC");
1607         if( papszMD != nullptr )
1608             poVDS->SetMetadata( papszMD, "RPC" );
1609 
1610         papszMD = poSrcDS->GetMetadata("GEOLOCATION");
1611         if( papszMD != nullptr )
1612             poVDS->SetMetadata( papszMD, "GEOLOCATION" );
1613     }
1614     else
1615     {
1616         char **papszMD = poSrcDS->GetMetadata("RPC");
1617         if( papszMD != nullptr )
1618         {
1619             papszMD = CSLDuplicate(papszMD);
1620 
1621             double dfSAMP_OFF = CPLAtof(CSLFetchNameValueDef(papszMD, "SAMP_OFF", "0"));
1622             double dfLINE_OFF = CPLAtof(CSLFetchNameValueDef(papszMD, "LINE_OFF", "0"));
1623             double dfSAMP_SCALE = CPLAtof(CSLFetchNameValueDef(papszMD, "SAMP_SCALE", "1"));
1624             double dfLINE_SCALE = CPLAtof(CSLFetchNameValueDef(papszMD, "LINE_SCALE", "1"));
1625 
1626             dfSAMP_OFF -= adfSrcWinOri[0];
1627             dfLINE_OFF -= adfSrcWinOri[1];
1628 
1629             const double df2 = adfSrcWinOri[2];
1630             const double df3 = adfSrcWinOri[3];
1631             dfSAMP_OFF *= nOXSize / df2;
1632             dfLINE_OFF *= nOYSize / df3;
1633             dfSAMP_SCALE *= nOXSize / df2;
1634             dfLINE_SCALE *= nOYSize / df3;
1635 
1636             CPLString osField;
1637             osField.Printf( "%.15g", dfLINE_OFF );
1638             papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
1639 
1640             osField.Printf( "%.15g", dfSAMP_OFF );
1641             papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
1642 
1643             osField.Printf( "%.15g", dfLINE_SCALE );
1644             papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
1645 
1646             osField.Printf( "%.15g", dfSAMP_SCALE );
1647             papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
1648 
1649             poVDS->SetMetadata( papszMD, "RPC" );
1650             CSLDestroy(papszMD);
1651         }
1652     }
1653 
1654     const int nSrcBandCount = psOptions->nBandCount;
1655 
1656     if (psOptions->nRGBExpand != 0)
1657     {
1658         GDALRasterBand *poSrcBand =
1659             static_cast<GDALDataset*>(hSrcDataset)->
1660                 GetRasterBand(std::abs(psOptions->panBandList[0]));
1661         if (psOptions->panBandList[0] < 0)
1662             poSrcBand = poSrcBand->GetMaskBand();
1663         GDALColorTable* poColorTable = poSrcBand->GetColorTable();
1664         if (poColorTable == nullptr)
1665         {
1666             CPLError(CE_Failure, CPLE_AppDefined,
1667                      "Error : band %d has no color table",
1668                      std::abs(psOptions->panBandList[0]));
1669             GDALClose(poVDS);
1670             GDALTranslateOptionsFree(psOptions);
1671             return nullptr;
1672         }
1673 
1674         /* Check that the color table only contains gray levels */
1675         /* when using -expand gray */
1676         if (psOptions->nRGBExpand == 1)
1677         {
1678             int nColorCount = poColorTable->GetColorEntryCount();
1679             for( int nColor = 0; nColor < nColorCount; nColor++ )
1680             {
1681                 const GDALColorEntry* poEntry = poColorTable->GetColorEntry(nColor);
1682                 if (poEntry->c1 != poEntry->c2 || poEntry->c1 != poEntry->c3)
1683                 {
1684                     CPLError( CE_Warning, CPLE_AppDefined, "Warning : color table contains non gray levels colors");
1685                     break;
1686                 }
1687             }
1688         }
1689 
1690         if (psOptions->nBandCount == 1)
1691         {
1692             psOptions->nBandCount = psOptions->nRGBExpand;
1693         }
1694         else if (psOptions->nBandCount == 2 && (psOptions->nRGBExpand == 3 || psOptions->nRGBExpand == 4))
1695         {
1696             psOptions->nBandCount = psOptions->nRGBExpand;
1697         }
1698         else
1699         {
1700             CPLError( CE_Failure, CPLE_IllegalArg, "Error : invalid use of -expand option.");
1701             GDALClose(poVDS);
1702             GDALTranslateOptionsFree(psOptions);
1703             return nullptr;
1704         }
1705     }
1706 
1707     // Can be set to TRUE in the band loop too
1708     bool bFilterOutStatsMetadata =
1709         psOptions->nScaleRepeat > 0 || psOptions->bUnscale ||
1710         !bSpatialArrangementPreserved || psOptions->nRGBExpand != 0;
1711 
1712     if( psOptions->nColorInterpSize > psOptions->nBandCount )
1713     {
1714         CPLError(CE_Warning, CPLE_AppDefined,
1715                  "More bands defined in -colorinterp than output bands");
1716     }
1717 
1718 /* ==================================================================== */
1719 /*      Process all bands.                                              */
1720 /* ==================================================================== */
1721     for( int i = 0; i < psOptions->nBandCount; i++ )
1722     {
1723         int nComponent = 0;
1724         int nSrcBand = 0;
1725 
1726         if (psOptions->nRGBExpand != 0)
1727         {
1728             if (nSrcBandCount == 2 && psOptions->nRGBExpand == 4 && i == 3)
1729                 nSrcBand = psOptions->panBandList[1];
1730             else
1731             {
1732                 nSrcBand = psOptions->panBandList[0];
1733                 nComponent = i + 1;
1734             }
1735         }
1736         else
1737         {
1738             nSrcBand = psOptions->panBandList[i];
1739         }
1740 
1741         GDALRasterBand *poSrcBand =
1742             static_cast<GDALDataset*>(hSrcDataset)->GetRasterBand(std::abs(nSrcBand));
1743 
1744 /* -------------------------------------------------------------------- */
1745 /*      Select output data type to match source.                        */
1746 /* -------------------------------------------------------------------- */
1747         GDALRasterBand* poRealSrcBand =
1748                 (nSrcBand < 0) ? poSrcBand->GetMaskBand(): poSrcBand;
1749         GDALDataType eBandType;
1750         if( psOptions->eOutputType == GDT_Unknown )
1751         {
1752             eBandType = poRealSrcBand->GetRasterDataType();
1753         }
1754         else
1755         {
1756             eBandType = psOptions->eOutputType;
1757 
1758             // Check that we can copy existing statistics
1759             GDALDataType eSrcBandType = poRealSrcBand->GetRasterDataType();
1760             const char* pszMin = poRealSrcBand->GetMetadataItem("STATISTICS_MINIMUM");
1761             const char* pszMax = poRealSrcBand->GetMetadataItem("STATISTICS_MAXIMUM");
1762             if( !bFilterOutStatsMetadata && eBandType != eSrcBandType &&
1763                 pszMin != nullptr && pszMax != nullptr )
1764             {
1765                 const bool bSrcIsInteger =
1766                     CPL_TO_BOOL(GDALDataTypeIsInteger(eSrcBandType) &&
1767                                 !GDALDataTypeIsComplex(eSrcBandType));
1768                 const bool bDstIsInteger =
1769                     CPL_TO_BOOL(GDALDataTypeIsInteger(eBandType) &&
1770                                 !GDALDataTypeIsComplex(eBandType));
1771                 if( bSrcIsInteger && bDstIsInteger )
1772                 {
1773                     GInt32 nDstMin = 0;
1774                     GUInt32 nDstMax = 0;
1775                     switch( eBandType )
1776                     {
1777                         case GDT_Byte:
1778                             nDstMin = 0;
1779                             nDstMax = 255;
1780                             break;
1781                         case GDT_UInt16:
1782                             nDstMin = 0;
1783                             nDstMax = 65535;
1784                             break;
1785                         case GDT_Int16:
1786                             nDstMin = -32768;
1787                             nDstMax = 32767;
1788                             break;
1789                         case GDT_UInt32:
1790                             nDstMin = 0;
1791                             nDstMax = 0xFFFFFFFFU;
1792                             break;
1793                         case GDT_Int32:
1794                             nDstMin = 0x80000000;
1795                             nDstMax = 0x7FFFFFFF;
1796                             break;
1797                         default:
1798                             CPLAssert(false);
1799                             break;
1800                     }
1801 
1802                     GInt32 nMin = atoi(pszMin);
1803                     GUInt32 nMax = static_cast<GUInt32>(strtoul(pszMax, nullptr, 10));
1804                     if( nMin < nDstMin || nMax > nDstMax )
1805                         bFilterOutStatsMetadata = true;
1806                 }
1807                 // Float64 is large enough to hold all integer <= 32 bit or float32 values
1808                 // there might be other OK cases, but ere on safe side for now
1809                 else if( !((bSrcIsInteger || eSrcBandType == GDT_Float32) && eBandType == GDT_Float64) )
1810                 {
1811                     bFilterOutStatsMetadata = true;
1812                 }
1813             }
1814         }
1815 
1816 /* -------------------------------------------------------------------- */
1817 /*      Create this band.                                               */
1818 /* -------------------------------------------------------------------- */
1819         CPLStringList aosAddBandOptions;
1820         if( bSpatialArrangementPreserved )
1821         {
1822             int nSrcBlockXSize, nSrcBlockYSize;
1823             poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
1824             aosAddBandOptions.SetNameValue("BLOCKXSIZE", CPLSPrintf("%d", nSrcBlockXSize));
1825             aosAddBandOptions.SetNameValue("BLOCKYSIZE", CPLSPrintf("%d", nSrcBlockYSize));
1826         }
1827         poVDS->AddBand( eBandType, aosAddBandOptions.List() );
1828         VRTSourcedRasterBand *poVRTBand =
1829             static_cast<VRTSourcedRasterBand *>(poVDS->GetRasterBand( i+1 ));
1830         if (nSrcBand < 0)
1831         {
1832             poVRTBand->AddMaskBandSource(poSrcBand,
1833                                          psOptions->adfSrcWin[0], psOptions->adfSrcWin[1],
1834                                          psOptions->adfSrcWin[2], psOptions->adfSrcWin[3],
1835                                          adfDstWin[0], adfDstWin[1],
1836                                          adfDstWin[2], adfDstWin[3]);
1837             continue;
1838         }
1839 
1840         // Preserve NBITS if no option change values
1841         const char* pszNBits = poSrcBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
1842         if( pszNBits && psOptions->nRGBExpand == 0 && psOptions->nScaleRepeat == 0 &&
1843             !psOptions->bUnscale && psOptions->eOutputType == GDT_Unknown && psOptions->pszResampling == nullptr )
1844         {
1845             poVRTBand->SetMetadataItem("NBITS", pszNBits, "IMAGE_STRUCTURE");
1846         }
1847 
1848         // Preserve PIXELTYPE if no option change values
1849         const char* pszPixelType = poSrcBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
1850         if( pszPixelType && psOptions->nRGBExpand == 0 && psOptions->nScaleRepeat == 0 &&
1851             !psOptions->bUnscale && psOptions->eOutputType == GDT_Unknown && psOptions->pszResampling == nullptr )
1852         {
1853             poVRTBand->SetMetadataItem("PIXELTYPE", pszPixelType, "IMAGE_STRUCTURE");
1854         }
1855 
1856         const char* pszCompression = poSrcBand->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE");
1857         if( pszCompression )
1858         {
1859             poVRTBand->SetMetadataItem("COMPRESSION", pszCompression, "IMAGE_STRUCTURE");
1860         }
1861 
1862 /* -------------------------------------------------------------------- */
1863 /*      Do we need to collect scaling information?                      */
1864 /* -------------------------------------------------------------------- */
1865         double dfScale = 1.0;
1866         double dfOffset = 0.0;
1867         int bScale = FALSE;
1868         bool bHaveScaleSrc = false;
1869         double dfScaleSrcMin = 0.0;
1870         double dfScaleSrcMax = 0.0;
1871         double dfScaleDstMin = 0.0;
1872         double dfScaleDstMax = 0.0;
1873         bool bExponentScaling = false;
1874         double dfExponent = 0.0;
1875 
1876         // TODO(schwehr): Is bScale a bool?
1877         if( i < psOptions->nScaleRepeat && psOptions->pasScaleParams[i].bScale )
1878         {
1879             bScale = psOptions->pasScaleParams[i].bScale;
1880             bHaveScaleSrc = psOptions->pasScaleParams[i].bHaveScaleSrc;
1881             dfScaleSrcMin = psOptions->pasScaleParams[i].dfScaleSrcMin;
1882             dfScaleSrcMax = psOptions->pasScaleParams[i].dfScaleSrcMax;
1883             dfScaleDstMin = psOptions->pasScaleParams[i].dfScaleDstMin;
1884             dfScaleDstMax = psOptions->pasScaleParams[i].dfScaleDstMax;
1885         }
1886         else if( psOptions->nScaleRepeat == 1 && !psOptions->bHasUsedExplicitScaleBand )
1887         {
1888             bScale = psOptions->pasScaleParams[0].bScale;
1889             bHaveScaleSrc = psOptions->pasScaleParams[0].bHaveScaleSrc;
1890             dfScaleSrcMin = psOptions->pasScaleParams[0].dfScaleSrcMin;
1891             dfScaleSrcMax = psOptions->pasScaleParams[0].dfScaleSrcMax;
1892             dfScaleDstMin = psOptions->pasScaleParams[0].dfScaleDstMin;
1893             dfScaleDstMax = psOptions->pasScaleParams[0].dfScaleDstMax;
1894         }
1895 
1896         if( i < psOptions->nExponentRepeat && psOptions->padfExponent[i] != 0.0 )
1897         {
1898             bExponentScaling = TRUE;
1899             dfExponent = psOptions->padfExponent[i];
1900         }
1901         else if( psOptions->nExponentRepeat == 1 && !psOptions->bHasUsedExplicitExponentBand )
1902         {
1903             bExponentScaling = TRUE;
1904             dfExponent = psOptions->padfExponent[0];
1905         }
1906 
1907         if( bExponentScaling && !bScale )
1908         {
1909             CPLError( CE_Failure, CPLE_IllegalArg, "For band %d, -scale should be specified when -exponent is specified.", i + 1);
1910             if(pbUsageError)
1911                 *pbUsageError = TRUE;
1912             GDALTranslateOptionsFree(psOptions);
1913             delete poVDS;
1914             return nullptr;
1915         }
1916 
1917         if( bScale && !bHaveScaleSrc )
1918         {
1919             double adfCMinMax[2] = {};
1920             GDALComputeRasterMinMax( poSrcBand, TRUE, adfCMinMax );
1921             dfScaleSrcMin = adfCMinMax[0];
1922             dfScaleSrcMax = adfCMinMax[1];
1923         }
1924 
1925         if( bScale )
1926         {
1927             /* To avoid a divide by zero */
1928             if( dfScaleSrcMax == dfScaleSrcMin )
1929                 dfScaleSrcMax += 0.1;
1930 
1931             // Can still occur for very big values
1932             if( dfScaleSrcMax == dfScaleSrcMin )
1933             {
1934                 CPLError( CE_Failure, CPLE_AppDefined,
1935                           "-scale cannot be applied due to source "
1936                           "minimum and maximum being equal" );
1937                 GDALTranslateOptionsFree(psOptions);
1938                 delete poVDS;
1939                 return nullptr;
1940             }
1941 
1942             if( !bExponentScaling )
1943             {
1944                 dfScale = (dfScaleDstMax - dfScaleDstMin)
1945                     / (dfScaleSrcMax - dfScaleSrcMin);
1946                 dfOffset = -1 * dfScaleSrcMin * dfScale + dfScaleDstMin;
1947             }
1948         }
1949 
1950         if( psOptions->bUnscale )
1951         {
1952             dfScale = poSrcBand->GetScale();
1953             dfOffset = poSrcBand->GetOffset();
1954         }
1955 
1956 /* -------------------------------------------------------------------- */
1957 /*      Create a simple or complex data source depending on the         */
1958 /*      translation type required.                                      */
1959 /* -------------------------------------------------------------------- */
1960         VRTSimpleSource* poSimpleSource = nullptr;
1961         if( psOptions->bUnscale || bScale || (psOptions->nRGBExpand != 0 && i < psOptions->nRGBExpand) )
1962         {
1963             VRTComplexSource* poSource = new VRTComplexSource();
1964 
1965         /* -------------------------------------------------------------------- */
1966         /*      Set complex parameters.                                         */
1967         /* -------------------------------------------------------------------- */
1968 
1969             if( dfOffset != 0.0 || dfScale != 1.0 )
1970             {
1971                 poSource->SetLinearScaling(dfOffset, dfScale);
1972             }
1973             else if( bExponentScaling )
1974             {
1975                 poSource->SetPowerScaling(dfExponent,
1976                                           dfScaleSrcMin,
1977                                           dfScaleSrcMax,
1978                                           dfScaleDstMin,
1979                                           dfScaleDstMax);
1980             }
1981 
1982             poSource->SetColorTableComponent(nComponent);
1983 
1984             int bSuccess;
1985             double dfNoData = poSrcBand->GetNoDataValue( &bSuccess );
1986             if ( bSuccess )
1987             {
1988                 poSource->SetNoDataValue(dfNoData);
1989             }
1990 
1991             poSimpleSource = poSource;
1992         }
1993         else
1994         {
1995             poSimpleSource = new VRTSimpleSource();
1996         }
1997 
1998         poSimpleSource->SetResampling(psOptions->pszResampling);
1999         poVRTBand->ConfigureSource( poSimpleSource,
2000                                     poSrcBand,
2001                                     FALSE,
2002                                     psOptions->adfSrcWin[0], psOptions->adfSrcWin[1],
2003                                     psOptions->adfSrcWin[2], psOptions->adfSrcWin[3],
2004                                     adfDstWin[0], adfDstWin[1],
2005                                     adfDstWin[2], adfDstWin[3] );
2006 
2007         poVRTBand->AddSource( poSimpleSource );
2008 
2009 /* -------------------------------------------------------------------- */
2010 /*      In case of color table translate, we only set the color         */
2011 /*      interpretation other info copied by CopyBandInfo are            */
2012 /*      not relevant in RGB expansion.                                  */
2013 /* -------------------------------------------------------------------- */
2014         if (psOptions->nRGBExpand == 1)
2015         {
2016             poVRTBand->SetColorInterpretation( GCI_GrayIndex );
2017         }
2018         else if (psOptions->nRGBExpand != 0 && i < psOptions->nRGBExpand)
2019         {
2020             poVRTBand->SetColorInterpretation( static_cast<GDALColorInterp>(GCI_RedBand + i) );
2021         }
2022 
2023 /* -------------------------------------------------------------------- */
2024 /*      copy over some other information of interest.                   */
2025 /* -------------------------------------------------------------------- */
2026         else
2027         {
2028             CopyBandInfo( poSrcBand, poVRTBand,
2029                           !psOptions->bStats && !bFilterOutStatsMetadata,
2030                           !psOptions->bUnscale && !psOptions->bSetScale &&
2031                             !psOptions->bSetOffset,
2032                           !psOptions->bSetNoData && !psOptions->bUnsetNoData,
2033                           !psOptions->bNoRAT,
2034                           psOptions );
2035             if( psOptions->nScaleRepeat == 0 &&
2036                 psOptions->nExponentRepeat == 0 &&
2037                 EQUAL(psOptions->pszFormat, "GRIB") )
2038             {
2039                 char** papszMD_GRIB = poSrcBand->GetMetadata("GRIB");
2040                 if( papszMD_GRIB != nullptr)
2041                     poVRTBand->SetMetadata( papszMD_GRIB, "GRIB" );
2042             }
2043         }
2044 
2045         // Color interpretation override
2046         if( psOptions->panColorInterp )
2047         {
2048             if( i < psOptions->nColorInterpSize &&
2049                 psOptions->panColorInterp[i] >= 0 )
2050             {
2051                 poVRTBand->SetColorInterpretation(
2052                     static_cast<GDALColorInterp>(psOptions->panColorInterp[i]));
2053             }
2054         }
2055 
2056 /* -------------------------------------------------------------------- */
2057 /*      Set a forcible nodata value?                                    */
2058 /* -------------------------------------------------------------------- */
2059         if( psOptions->bSetNoData )
2060         {
2061             const double dfVal = AdjustNoDataValue(
2062                 psOptions->dfNoDataReal, poVRTBand, psOptions);
2063             poVRTBand->SetNoDataValue( dfVal );
2064         }
2065 
2066         if( psOptions->bSetScale )
2067             poVRTBand->SetScale( psOptions->dfScale );
2068 
2069         if( psOptions->bSetOffset )
2070             poVRTBand->SetOffset( psOptions->dfOffset );
2071 
2072         if (psOptions->eMaskMode == MASK_AUTO &&
2073             (GDALGetMaskFlags(GDALGetRasterBand(hSrcDataset, 1)) & GMF_PER_DATASET) == 0 &&
2074             (poSrcBand->GetMaskFlags() & (GMF_ALL_VALID | GMF_NODATA)) == 0)
2075         {
2076             if (poVRTBand->CreateMaskBand(poSrcBand->GetMaskFlags()) == CE_None)
2077             {
2078                 VRTSourcedRasterBand* hMaskVRTBand =
2079                     cpl::down_cast<VRTSourcedRasterBand*>(poVRTBand->GetMaskBand());
2080                 hMaskVRTBand->AddMaskBandSource(poSrcBand,
2081                                         psOptions->adfSrcWin[0], psOptions->adfSrcWin[1],
2082                                         psOptions->adfSrcWin[2], psOptions->adfSrcWin[3],
2083                                         adfDstWin[0], adfDstWin[1],
2084                                         adfDstWin[2], adfDstWin[3] );
2085             }
2086         }
2087     }
2088 
2089     if (psOptions->eMaskMode == MASK_USER)
2090     {
2091         GDALRasterBand *poSrcBand =
2092             static_cast<GDALRasterBand*>(GDALGetRasterBand(hSrcDataset,
2093                                                std::abs(psOptions->nMaskBand)));
2094         if (poSrcBand && poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
2095         {
2096             VRTSourcedRasterBand* hMaskVRTBand = static_cast<VRTSourcedRasterBand*>(
2097                 GDALGetMaskBand(GDALGetRasterBand(static_cast<GDALDataset*>(poVDS), 1)));
2098             if (psOptions->nMaskBand > 0)
2099                 hMaskVRTBand->AddSimpleSource(poSrcBand,
2100                                         psOptions->adfSrcWin[0], psOptions->adfSrcWin[1],
2101                                         psOptions->adfSrcWin[2], psOptions->adfSrcWin[3],
2102                                         adfDstWin[0], adfDstWin[1],
2103                                         adfDstWin[2], adfDstWin[3] );
2104             else
2105                 hMaskVRTBand->AddMaskBandSource(poSrcBand,
2106                                         psOptions->adfSrcWin[0], psOptions->adfSrcWin[1],
2107                                         psOptions->adfSrcWin[2], psOptions->adfSrcWin[3],
2108                                         adfDstWin[0], adfDstWin[1],
2109                                         adfDstWin[2], adfDstWin[3] );
2110         }
2111     }
2112     else
2113     if (psOptions->eMaskMode == MASK_AUTO && nSrcBandCount > 0 &&
2114         GDALGetMaskFlags(GDALGetRasterBand(hSrcDataset, 1)) == GMF_PER_DATASET)
2115     {
2116         if (poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
2117         {
2118             VRTSourcedRasterBand* hMaskVRTBand = static_cast<VRTSourcedRasterBand*>(
2119                 GDALGetMaskBand(GDALGetRasterBand(static_cast<GDALDataset*>(poVDS), 1)));
2120             hMaskVRTBand->AddMaskBandSource(static_cast<GDALRasterBand*>(GDALGetRasterBand(hSrcDataset, 1)),
2121                                         psOptions->adfSrcWin[0], psOptions->adfSrcWin[1],
2122                                         psOptions->adfSrcWin[2], psOptions->adfSrcWin[3],
2123                                         adfDstWin[0], adfDstWin[1],
2124                                         adfDstWin[2], adfDstWin[3] );
2125         }
2126     }
2127 
2128 /* -------------------------------------------------------------------- */
2129 /*      Compute stats if required.                                      */
2130 /* -------------------------------------------------------------------- */
2131     if (psOptions->bStats)
2132     {
2133         for( int i = 0; i < poVDS->GetRasterCount(); i++ )
2134         {
2135             double dfMin, dfMax, dfMean, dfStdDev;
2136             poVDS->GetRasterBand(i+1)->ComputeStatistics( psOptions->bApproxStats,
2137                     &dfMin, &dfMax, &dfMean, &dfStdDev, GDALDummyProgress, nullptr );
2138         }
2139     }
2140 
2141 /* -------------------------------------------------------------------- */
2142 /*      Write to the output file using CopyCreate().                    */
2143 /* -------------------------------------------------------------------- */
2144     if( EQUAL(psOptions->pszFormat, "VRT") &&
2145         psOptions->papszCreateOptions == nullptr )
2146     {
2147         poVDS->SetDescription(pszDest);
2148         hOutDS = static_cast<GDALDatasetH>(poVDS);
2149         if( !EQUAL(pszDest, "") )
2150         {
2151             hOutDS = GDALTranslateFlush(hOutDS);
2152         }
2153     }
2154     else
2155     {
2156         hOutDS = GDALCreateCopy( hDriver, pszDest, static_cast<GDALDatasetH>(poVDS),
2157                                 psOptions->bStrict, psOptions->papszCreateOptions,
2158                                 psOptions->pfnProgress, psOptions->pProgressData );
2159         hOutDS = GDALTranslateFlush(hOutDS);
2160 
2161         GDALClose(poVDS);
2162     }
2163 
2164     GDALTranslateOptionsFree(psOptions);
2165     return hOutDS;
2166 }
2167 
2168 /************************************************************************/
2169 /*                           AttachMetadata()                           */
2170 /************************************************************************/
2171 
AttachMetadata(GDALDatasetH hDS,char ** papszMetadataOptions)2172 static void AttachMetadata( GDALDatasetH hDS, char **papszMetadataOptions )
2173 
2174 {
2175     const int nCount = CSLCount(papszMetadataOptions);
2176 
2177     for( int i = 0; i < nCount; i++ )
2178     {
2179         char *pszKey = nullptr;
2180         const char *pszValue =
2181             CPLParseNameValue(papszMetadataOptions[i], &pszKey);
2182         if( pszKey && pszValue )
2183         {
2184             GDALSetMetadataItem(hDS,pszKey,pszValue,nullptr);
2185         }
2186         CPLFree( pszKey );
2187     }
2188 }
2189 
2190 /************************************************************************/
2191 /*                           CopyBandInfo()                            */
2192 /************************************************************************/
2193 
2194 /* A bit of a clone of VRTRasterBand::CopyCommonInfoFrom(), but we need */
2195 /* more and more custom behavior in the context of gdal_translate ... */
2196 
CopyBandInfo(GDALRasterBand * poSrcBand,GDALRasterBand * poDstBand,int bCanCopyStatsMetadata,int bCopyScale,int bCopyNoData,bool bCopyRAT,const GDALTranslateOptions * psOptions)2197 static void CopyBandInfo( GDALRasterBand * poSrcBand, GDALRasterBand * poDstBand,
2198                           int bCanCopyStatsMetadata, int bCopyScale, int bCopyNoData, bool bCopyRAT,
2199                           const GDALTranslateOptions *psOptions )
2200 
2201 {
2202 
2203     if (bCanCopyStatsMetadata)
2204     {
2205         poDstBand->SetMetadata( poSrcBand->GetMetadata() );
2206         if (bCopyRAT)
2207         {
2208             poDstBand->SetDefaultRAT( poSrcBand->GetDefaultRAT() );
2209         }
2210     }
2211     else
2212     {
2213         char** papszMetadata = poSrcBand->GetMetadata();
2214         char** papszMetadataNew = nullptr;
2215         for( int i = 0; papszMetadata != nullptr && papszMetadata[i] != nullptr; i++ )
2216         {
2217             if (!STARTS_WITH(papszMetadata[i], "STATISTICS_"))
2218                 papszMetadataNew = CSLAddString(papszMetadataNew, papszMetadata[i]);
2219         }
2220         poDstBand->SetMetadata( papszMetadataNew );
2221         CSLDestroy(papszMetadataNew);
2222 
2223         // we need to strip histogram data from the source RAT
2224         if (poSrcBand->GetDefaultRAT() && bCopyRAT)
2225         {
2226             GDALRasterAttributeTable *poNewRAT = poSrcBand->GetDefaultRAT()->Clone();
2227 
2228             // strip histogram data (as defined by the source RAT)
2229             poNewRAT->RemoveStatistics();
2230             if( poNewRAT->GetColumnCount() )
2231             {
2232                 poDstBand->SetDefaultRAT( poNewRAT );
2233             }
2234             // since SetDefaultRAT copies the RAT data we need to delete our original
2235             delete poNewRAT;
2236         }
2237     }
2238 
2239     poDstBand->SetColorTable( poSrcBand->GetColorTable() );
2240     poDstBand->SetColorInterpretation(poSrcBand->GetColorInterpretation());
2241     if( strlen(poSrcBand->GetDescription()) > 0 )
2242         poDstBand->SetDescription( poSrcBand->GetDescription() );
2243 
2244     if (bCopyNoData)
2245     {
2246         int bSuccess = FALSE;
2247         double dfNoData = poSrcBand->GetNoDataValue(&bSuccess);
2248         if( bSuccess )
2249         {
2250             const double dfVal = AdjustNoDataValue(
2251                 dfNoData, poDstBand, psOptions);
2252             poDstBand->SetNoDataValue( dfVal );
2253         }
2254     }
2255 
2256     if (bCopyScale)
2257     {
2258         poDstBand->SetOffset( poSrcBand->GetOffset() );
2259         poDstBand->SetScale( poSrcBand->GetScale() );
2260     }
2261 
2262     poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() );
2263 
2264     // Copy unit only if the range of pixel values is not modified
2265     if( bCanCopyStatsMetadata && bCopyScale && !EQUAL(poSrcBand->GetUnitType(),"") )
2266         poDstBand->SetUnitType( poSrcBand->GetUnitType() );
2267 }
2268 
2269 /************************************************************************/
2270 /*                            ArgIsNumeric()                            */
2271 /************************************************************************/
2272 
ArgIsNumeric(const char * pszArg)2273 int ArgIsNumeric( const char *pszArg )
2274 
2275 {
2276     return CPLGetValueType(pszArg) != CPL_VALUE_STRING;
2277 }
2278 
2279 /************************************************************************/
2280 /*                             GetColorInterp()                         */
2281 /************************************************************************/
2282 
GetColorInterp(const char * pszStr)2283 static int GetColorInterp( const char* pszStr )
2284 {
2285     if( EQUAL(pszStr, "red") )
2286         return GCI_RedBand;
2287     if( EQUAL(pszStr, "green") )
2288         return GCI_GreenBand;
2289     if( EQUAL(pszStr, "blue") )
2290         return GCI_BlueBand;
2291     if( EQUAL(pszStr, "alpha") )
2292         return GCI_AlphaBand;
2293     if( EQUAL(pszStr, "gray") || EQUAL(pszStr, "grey") )
2294         return GCI_GrayIndex;
2295     if( EQUAL(pszStr, "undefined") )
2296         return GCI_Undefined;
2297     CPLError(CE_Warning, CPLE_NotSupported,
2298              "Unsupported color interpretation: %s", pszStr);
2299     return -1;
2300 }
2301 
2302 /************************************************************************/
2303 /*                             GDALTranslateOptionsNew()                */
2304 /************************************************************************/
2305 
2306 /**
2307  * Allocates a GDALTranslateOptions struct.
2308  *
2309  * @param papszArgv NULL terminated list of options (potentially including filename and open options too), or NULL.
2310  *                  The accepted options are the ones of the <a href="/programs/gdal_translate.html">gdal_translate</a> utility.
2311  * @param psOptionsForBinary (output) may be NULL (and should generally be NULL),
2312  *                           otherwise (gdal_translate_bin.cpp use case) must be allocated with
2313  *                           GDALTranslateOptionsForBinaryNew() prior to this function. Will be
2314  *                           filled with potentially present filename, open options,...
2315  * @return pointer to the allocated GDALTranslateOptions struct. Must be freed with GDALTranslateOptionsFree().
2316  *
2317  * @since GDAL 2.1
2318  */
2319 
GDALTranslateOptionsNew(char ** papszArgv,GDALTranslateOptionsForBinary * psOptionsForBinary)2320 GDALTranslateOptions *GDALTranslateOptionsNew(char** papszArgv, GDALTranslateOptionsForBinary* psOptionsForBinary)
2321 {
2322     GDALTranslateOptions *psOptions = static_cast<GDALTranslateOptions *>(
2323         CPLCalloc( 1, sizeof(GDALTranslateOptions)));
2324 
2325     psOptions->pszFormat = nullptr;
2326     psOptions->bQuiet = true;
2327     psOptions->pfnProgress = GDALDummyProgress;
2328     psOptions->pProgressData = nullptr;
2329     psOptions->eOutputType = GDT_Unknown;
2330     psOptions->eMaskMode = MASK_AUTO;
2331     psOptions->nBandCount = 0;
2332     psOptions->panBandList = nullptr;
2333     psOptions->nOXSizePixel = 0;
2334     psOptions->nOYSizePixel = 0;
2335     psOptions->dfOXSizePct = 0.0;
2336     psOptions->dfOYSizePct = 0.0;
2337     psOptions->adfSrcWin[0] = 0;
2338     psOptions->adfSrcWin[1] = 0;
2339     psOptions->adfSrcWin[2] = 0;
2340     psOptions->adfSrcWin[3] = 0;
2341     psOptions->bStrict = false;
2342     psOptions->bUnscale = false;
2343     psOptions->bSetScale = false;
2344     psOptions->dfScale = 1.0;
2345     psOptions->bSetOffset = false;
2346     psOptions->dfOffset = 0.0;
2347     psOptions->nScaleRepeat = 0;
2348     psOptions->pasScaleParams = nullptr;
2349     psOptions->bHasUsedExplicitScaleBand = false;
2350     psOptions->nExponentRepeat = 0;
2351     psOptions->padfExponent = nullptr;
2352     psOptions->bHasUsedExplicitExponentBand = false;
2353     psOptions->dfULX = 0.0;
2354     psOptions->dfULY = 0.0;
2355     psOptions->dfLRX = 0.0;
2356     psOptions->dfLRY = 0.0;
2357     psOptions->pszOutputSRS = nullptr;
2358     psOptions->bNoGCP = false;
2359     psOptions->nGCPCount = 0;
2360     psOptions->pasGCPs = nullptr;
2361     psOptions->adfULLR[0] = 0;
2362     psOptions->adfULLR[1] = 0;
2363     psOptions->adfULLR[2] = 0;
2364     psOptions->adfULLR[3] = 0;
2365     psOptions->bSetNoData = false;
2366     psOptions->bUnsetNoData = false;
2367     psOptions->dfNoDataReal = 0.0;
2368     psOptions->nRGBExpand = 0;
2369     psOptions->nMaskBand = 0;
2370     psOptions->bStats = false;
2371     psOptions->bApproxStats = false;
2372     psOptions->bErrorOnPartiallyOutside = false;
2373     psOptions->bErrorOnCompletelyOutside = false;
2374     psOptions->bNoRAT = false;
2375     psOptions->pszResampling = nullptr;
2376     psOptions->dfXRes = 0.0;
2377     psOptions->dfYRes = 0.0;
2378     psOptions->pszProjSRS = nullptr;
2379     psOptions->nLimitOutSize = 0;
2380     psOptions->bNoXMP = false;
2381 
2382     bool bParsedMaskArgument = false;
2383     bool bOutsideExplicitlySet = false;
2384     bool bGotSourceFilename = false;
2385     bool bGotDestFilename = false;
2386 
2387 /* -------------------------------------------------------------------- */
2388 /*      Handle command line arguments.                                  */
2389 /* -------------------------------------------------------------------- */
2390     const int argc = CSLCount(papszArgv);
2391     for( int i = 0; i < argc && papszArgv != nullptr && papszArgv[i] != nullptr; i++ )
2392     {
2393         if( i < argc-1 && (EQUAL(papszArgv[i],"-of") || EQUAL(papszArgv[i],"-f")) )
2394         {
2395             ++i;
2396             CPLFree(psOptions->pszFormat);
2397             psOptions->pszFormat = CPLStrdup(papszArgv[i]);
2398         }
2399 
2400         else if( EQUAL(papszArgv[i],"-q") || EQUAL(papszArgv[i],"-quiet") )
2401         {
2402             if( psOptionsForBinary )
2403                 psOptionsForBinary->bQuiet = true;
2404         }
2405 
2406         else if( EQUAL(papszArgv[i],"-ot") && papszArgv[i+1] )
2407         {
2408             for( int iType = 1; iType < GDT_TypeCount; iType++ )
2409             {
2410                 if( GDALGetDataTypeName(static_cast<GDALDataType>(iType)) != nullptr
2411                     && EQUAL(GDALGetDataTypeName(static_cast<GDALDataType>(iType)),
2412                              papszArgv[i+1]) )
2413                 {
2414                     psOptions->eOutputType = static_cast<GDALDataType>(iType);
2415                 }
2416             }
2417 
2418             if( psOptions->eOutputType == GDT_Unknown )
2419             {
2420                 CPLError(CE_Failure, CPLE_NotSupported,
2421                          "Unknown output pixel type: %s.", papszArgv[i+1] );
2422                 GDALTranslateOptionsFree(psOptions);
2423                 return nullptr;
2424             }
2425             i++;
2426         }
2427         else if( EQUAL(papszArgv[i],"-b") && papszArgv[i+1] )
2428         {
2429             const char* pszBand = papszArgv[i+1];
2430             bool bMask = false;
2431             if (EQUAL(pszBand, "mask"))
2432                 pszBand = "mask,1";
2433             if (STARTS_WITH_CI(pszBand, "mask,"))
2434             {
2435                 bMask = true;
2436                 pszBand += 5;
2437                 /* If we use the source mask band as a regular band */
2438                 /* don't create a target mask band by default */
2439                 if( !bParsedMaskArgument )
2440                     psOptions->eMaskMode = MASK_DISABLED;
2441             }
2442             const int nBand = atoi(pszBand);
2443             if( nBand < 1 )
2444             {
2445                 CPLError(CE_Failure, CPLE_NotSupported,"Unrecognizable band number (%s).", papszArgv[i+1] );
2446                 GDALTranslateOptionsFree(psOptions);
2447                 return nullptr;
2448             }
2449             i++;
2450 
2451             psOptions->nBandCount++;
2452             psOptions->panBandList = static_cast<int *>(
2453                 CPLRealloc(psOptions->panBandList,
2454                            sizeof(int) * psOptions->nBandCount));
2455             psOptions->panBandList[psOptions->nBandCount-1] = nBand;
2456             if (bMask)
2457                 psOptions->panBandList[psOptions->nBandCount-1] *= -1;
2458         }
2459         else if( EQUAL(papszArgv[i],"-mask") &&  papszArgv[i+1] )
2460         {
2461             bParsedMaskArgument = true;
2462             const char* pszBand = papszArgv[i+1];
2463             if (EQUAL(pszBand, "none"))
2464             {
2465                 psOptions->eMaskMode = MASK_DISABLED;
2466             }
2467             else if (EQUAL(pszBand, "auto"))
2468             {
2469                 psOptions->eMaskMode = MASK_AUTO;
2470             }
2471             else
2472             {
2473                 bool bMask = false;
2474                 if (EQUAL(pszBand, "mask"))
2475                     pszBand = "mask,1";
2476                 if (STARTS_WITH_CI(pszBand, "mask,"))
2477                 {
2478                     bMask = true;
2479                     pszBand += 5;
2480                 }
2481                 const int nBand = atoi(pszBand);
2482                 if( nBand < 1 )
2483                 {
2484                     CPLError(CE_Failure, CPLE_NotSupported,"Unrecognizable band number (%s).", papszArgv[i+1] );
2485                     GDALTranslateOptionsFree(psOptions);
2486                     return nullptr;
2487                 }
2488 
2489                 psOptions->eMaskMode = MASK_USER;
2490                 psOptions->nMaskBand = nBand;
2491                 if (bMask)
2492                     psOptions->nMaskBand *= -1;
2493             }
2494             i ++;
2495         }
2496         else if( EQUAL(papszArgv[i],"-not_strict") )
2497         {
2498             psOptions->bStrict = false;
2499 
2500         }
2501         else if( EQUAL(papszArgv[i],"-strict")  )
2502         {
2503             psOptions->bStrict = true;
2504         }
2505         else if( EQUAL(papszArgv[i],"-sds")  )
2506         {
2507             if( psOptionsForBinary )
2508                 psOptionsForBinary->bCopySubDatasets = TRUE;
2509         }
2510         else if (EQUAL(papszArgv[i], "-nogcp"))
2511         {
2512             psOptions->bNoGCP = true;
2513         }
2514         else if( i + 4 < argc && EQUAL(papszArgv[i],"-gcp") )
2515         {
2516             /* -gcp pixel line easting northing [elev] */
2517             psOptions->nGCPCount++;
2518             psOptions->pasGCPs = static_cast<GDAL_GCP *>(
2519                 CPLRealloc(psOptions->pasGCPs,
2520                            sizeof(GDAL_GCP) * psOptions->nGCPCount));
2521             GDALInitGCPs( 1, psOptions->pasGCPs + psOptions->nGCPCount - 1 );
2522 
2523             psOptions->pasGCPs[psOptions->nGCPCount-1].dfGCPPixel = CPLAtofM(papszArgv[++i]);
2524             psOptions->pasGCPs[psOptions->nGCPCount-1].dfGCPLine = CPLAtofM(papszArgv[++i]);
2525             psOptions->pasGCPs[psOptions->nGCPCount-1].dfGCPX = CPLAtofM(papszArgv[++i]);
2526             psOptions->pasGCPs[psOptions->nGCPCount-1].dfGCPY = CPLAtofM(papszArgv[++i]);
2527 
2528             char* endptr = nullptr;
2529             if( papszArgv[i+1] != nullptr
2530                 && (CPLStrtod(papszArgv[i+1], &endptr) != 0.0 || papszArgv[i+1][0] == '0') )
2531             {
2532                 /* Check that last argument is really a number and not a filename */
2533                 /* looking like a number (see ticket #863) */
2534                 if (endptr && *endptr == 0)
2535                     psOptions->pasGCPs[psOptions->nGCPCount-1].dfGCPZ = CPLAtofM(papszArgv[++i]);
2536             }
2537 
2538             /* should set id and info? */
2539         }
2540 
2541         else if( EQUAL(papszArgv[i],"-a_nodata") && papszArgv[i+1] )
2542         {
2543             if (EQUAL(papszArgv[i+1], "none"))
2544             {
2545                 psOptions->bUnsetNoData = true;
2546             }
2547             else
2548             {
2549                 psOptions->bSetNoData = true;
2550                 psOptions->dfNoDataReal = CPLAtofM(papszArgv[i+1]);
2551             }
2552             i += 1;
2553         }
2554 
2555         else if( EQUAL(papszArgv[i],"-a_scale") && papszArgv[i+1] )
2556         {
2557             psOptions->bSetScale = true;
2558             psOptions->dfScale = CPLAtofM(papszArgv[i+1]);
2559             i += 1;
2560         }
2561 
2562         else if( EQUAL(papszArgv[i],"-a_offset") && papszArgv[i+1] )
2563         {
2564             psOptions->bSetOffset = true;
2565             psOptions->dfOffset = CPLAtofM(papszArgv[i+1]);
2566             i += 1;
2567         }
2568 
2569 
2570         else if( i + 4 < argc && EQUAL(papszArgv[i],"-a_ullr") )
2571         {
2572             psOptions->adfULLR[0] = CPLAtofM(papszArgv[i+1]);
2573             psOptions->adfULLR[1] = CPLAtofM(papszArgv[i+2]);
2574             psOptions->adfULLR[2] = CPLAtofM(papszArgv[i+3]);
2575             psOptions->adfULLR[3] = CPLAtofM(papszArgv[i+4]);
2576 
2577             i += 4;
2578         }
2579 
2580         else if( EQUAL(papszArgv[i],"-co") && papszArgv[i+1] )
2581         {
2582             psOptions->papszCreateOptions = CSLAddString( psOptions->papszCreateOptions, papszArgv[++i] );
2583         }
2584 
2585         else if( EQUAL(papszArgv[i],"-scale") || STARTS_WITH_CI(papszArgv[i], "-scale_") )
2586         {
2587             int nIndex = 0;
2588             if( STARTS_WITH_CI(papszArgv[i], "-scale_") )
2589             {
2590                 if( !psOptions->bHasUsedExplicitScaleBand && psOptions->nScaleRepeat != 0 )
2591                 {
2592                     CPLError(CE_Failure, CPLE_NotSupported, "Cannot mix -scale and -scale_XX syntax");
2593                     GDALTranslateOptionsFree(psOptions);
2594                     return nullptr;
2595                 }
2596                 psOptions->bHasUsedExplicitScaleBand = true;
2597                 nIndex = atoi(papszArgv[i] + 7);
2598                 if( nIndex <= 0 || nIndex > 65535 )
2599                 {
2600                     CPLError(CE_Failure, CPLE_NotSupported, "Invalid parameter name: %s", papszArgv[i]);
2601                     GDALTranslateOptionsFree(psOptions);
2602                     return nullptr;
2603                 }
2604                 nIndex --;
2605             }
2606             else
2607             {
2608                 if( psOptions->bHasUsedExplicitScaleBand )
2609                 {
2610                     CPLError(CE_Failure, CPLE_NotSupported, "Cannot mix -scale and -scale_XX syntax");
2611                     GDALTranslateOptionsFree(psOptions);
2612                     return nullptr;
2613                 }
2614                 nIndex = psOptions->nScaleRepeat;
2615             }
2616 
2617             if( nIndex >= psOptions->nScaleRepeat )
2618             {
2619                 psOptions->pasScaleParams =
2620                     static_cast<GDALTranslateScaleParams*>(
2621                         CPLRealloc(psOptions->pasScaleParams,
2622                                    (nIndex + 1) *
2623                                    sizeof(GDALTranslateScaleParams)));
2624                 memset(psOptions->pasScaleParams + psOptions->nScaleRepeat, 0,
2625                         sizeof(GDALTranslateScaleParams) * (nIndex - psOptions->nScaleRepeat + 1));
2626                 psOptions->nScaleRepeat = nIndex + 1;
2627             }
2628             psOptions->pasScaleParams[nIndex].bScale = TRUE;
2629             psOptions->pasScaleParams[nIndex].bHaveScaleSrc = false;
2630             if( i < argc-2 && ArgIsNumeric(papszArgv[i+1]) )
2631             {
2632                 psOptions->pasScaleParams[nIndex].bHaveScaleSrc = true;
2633                 psOptions->pasScaleParams[nIndex].dfScaleSrcMin = CPLAtofM(papszArgv[i+1]);
2634                 psOptions->pasScaleParams[nIndex].dfScaleSrcMax = CPLAtofM(papszArgv[i+2]);
2635                 i += 2;
2636             }
2637             if( i < argc-2 && psOptions->pasScaleParams[nIndex].bHaveScaleSrc && ArgIsNumeric(papszArgv[i+1]) )
2638             {
2639                 psOptions->pasScaleParams[nIndex].dfScaleDstMin = CPLAtofM(papszArgv[i+1]);
2640                 psOptions->pasScaleParams[nIndex].dfScaleDstMax = CPLAtofM(papszArgv[i+2]);
2641                 i += 2;
2642             }
2643             else
2644             {
2645                 psOptions->pasScaleParams[nIndex].dfScaleDstMin = 0.0;
2646                 psOptions->pasScaleParams[nIndex].dfScaleDstMax = 255.999;
2647             }
2648         }
2649 
2650         else if( (EQUAL(papszArgv[i],"-exponent") || STARTS_WITH_CI(papszArgv[i], "-exponent_")) &&
2651                  papszArgv[i+1] )
2652         {
2653             int nIndex = 0;
2654             if( STARTS_WITH_CI(papszArgv[i], "-exponent_") )
2655             {
2656                 if( !psOptions->bHasUsedExplicitExponentBand && psOptions->nExponentRepeat != 0 )
2657                 {
2658                     CPLError(CE_Failure, CPLE_NotSupported, "Cannot mix -exponent and -exponent_XX syntax");
2659                     GDALTranslateOptionsFree(psOptions);
2660                     return nullptr;
2661                 }
2662                 psOptions->bHasUsedExplicitExponentBand = true;
2663                 nIndex = atoi(papszArgv[i] + 10);
2664                 if( nIndex <= 0 || nIndex > 65535 )
2665                 {
2666                     CPLError(CE_Failure, CPLE_NotSupported, "Invalid parameter name: %s", papszArgv[i]);
2667                     GDALTranslateOptionsFree(psOptions);
2668                     return nullptr;
2669                 }
2670                 nIndex --;
2671             }
2672             else
2673             {
2674                 if( psOptions->bHasUsedExplicitExponentBand )
2675                 {
2676                     CPLError(CE_Failure, CPLE_NotSupported, "Cannot mix -exponent and -exponent_XX syntax");
2677                     GDALTranslateOptionsFree(psOptions);
2678                     return nullptr;
2679                 }
2680                 nIndex = psOptions->nExponentRepeat;
2681             }
2682 
2683             if( nIndex >= psOptions->nExponentRepeat )
2684             {
2685               psOptions->padfExponent = static_cast<double *>(
2686                   CPLRealloc(psOptions->padfExponent,
2687                              (nIndex + 1) * sizeof(double)));
2688                 if( nIndex > psOptions->nExponentRepeat )
2689                     memset(psOptions->padfExponent + psOptions->nExponentRepeat, 0,
2690                         sizeof(double) * (nIndex - psOptions->nExponentRepeat));
2691                 psOptions->nExponentRepeat = nIndex + 1;
2692             }
2693             double dfExponent = CPLAtofM(papszArgv[++i]);
2694             psOptions->padfExponent[nIndex] = dfExponent;
2695         }
2696 
2697         else if( EQUAL(papszArgv[i], "-unscale") )
2698         {
2699             psOptions->bUnscale = true;
2700         }
2701 
2702         else if( EQUAL(papszArgv[i],"-mo") && papszArgv[i+1] )
2703         {
2704             psOptions->papszMetadataOptions = CSLAddString( psOptions->papszMetadataOptions,
2705                                                  papszArgv[++i] );
2706         }
2707 
2708         else if( i+2 < argc && EQUAL(papszArgv[i],"-outsize") && papszArgv[i+1] != nullptr )
2709         {
2710             ++i;
2711             if( papszArgv[i][0] != '\0' &&
2712                 papszArgv[i][strlen(papszArgv[i])-1] == '%' )
2713                 psOptions->dfOXSizePct = CPLAtofM(papszArgv[i]);
2714             else
2715                 psOptions->nOXSizePixel = atoi(papszArgv[i]);
2716             ++i;
2717             if( papszArgv[i][0] != '\0' &&
2718                 papszArgv[i][strlen(papszArgv[i])-1] == '%' )
2719                 psOptions->dfOYSizePct = CPLAtofM(papszArgv[i]);
2720             else
2721                 psOptions->nOYSizePixel = atoi(papszArgv[i]);
2722             bOutsideExplicitlySet = true;
2723         }
2724 
2725         else if( i+2 < argc && EQUAL(papszArgv[i],"-tr") )
2726         {
2727             psOptions->dfXRes = CPLAtofM(papszArgv[++i]);
2728             psOptions->dfYRes = fabs(CPLAtofM(papszArgv[++i]));
2729             if( psOptions->dfXRes == 0 || psOptions->dfYRes == 0 )
2730             {
2731                 CPLError(CE_Failure, CPLE_IllegalArg, "Wrong value for -tr parameters.");
2732                 GDALTranslateOptionsFree(psOptions);
2733                 return nullptr;
2734             }
2735         }
2736 
2737         else if( i+4 < argc && EQUAL(papszArgv[i],"-srcwin") )
2738         {
2739             psOptions->adfSrcWin[0] = CPLAtof(papszArgv[++i]);
2740             psOptions->adfSrcWin[1] = CPLAtof(papszArgv[++i]);
2741             psOptions->adfSrcWin[2] = CPLAtof(papszArgv[++i]);
2742             psOptions->adfSrcWin[3] = CPLAtof(papszArgv[++i]);
2743         }
2744 
2745         else if( i+4 < argc && EQUAL(papszArgv[i],"-projwin") )
2746         {
2747             psOptions->dfULX = CPLAtofM(papszArgv[++i]);
2748             psOptions->dfULY = CPLAtofM(papszArgv[++i]);
2749             psOptions->dfLRX = CPLAtofM(papszArgv[++i]);
2750             psOptions->dfLRY = CPLAtofM(papszArgv[++i]);
2751         }
2752 
2753         else if( i+1 < argc && EQUAL(papszArgv[i],"-projwin_srs") )
2754         {
2755             CPLFree(psOptions->pszProjSRS);
2756             psOptions->pszProjSRS = CPLStrdup(papszArgv[i+1]);
2757             i++;
2758         }
2759 
2760         else if( EQUAL(papszArgv[i],"-epo") )
2761         {
2762             psOptions->bErrorOnPartiallyOutside = true;
2763             psOptions->bErrorOnCompletelyOutside = true;
2764         }
2765 
2766         else  if( EQUAL(papszArgv[i],"-eco") )
2767         {
2768             psOptions->bErrorOnCompletelyOutside = true;
2769         }
2770 
2771         else if( i+1 < argc && EQUAL(papszArgv[i],"-a_srs") )
2772         {
2773             CPLFree(psOptions->pszOutputSRS);
2774             psOptions->pszOutputSRS = CPLStrdup(papszArgv[i+1]);
2775             i++;
2776         }
2777 
2778         else if( i+1 < argc && EQUAL(papszArgv[i],"-expand") && papszArgv[i+1] != nullptr )
2779         {
2780             i++;
2781             if (EQUAL(papszArgv[i], "gray"))
2782                 psOptions->nRGBExpand = 1;
2783             else if (EQUAL(papszArgv[i], "rgb"))
2784                 psOptions->nRGBExpand = 3;
2785             else if (EQUAL(papszArgv[i], "rgba"))
2786                 psOptions->nRGBExpand = 4;
2787             else
2788             {
2789                 CPLError(CE_Failure, CPLE_IllegalArg,
2790                          "Value %s unsupported. Only gray, rgb or rgba are supported.",
2791                           papszArgv[i] );
2792                 GDALTranslateOptionsFree(psOptions);
2793                 return nullptr;
2794             }
2795         }
2796 
2797         else if( EQUAL(papszArgv[i], "-stats") )
2798         {
2799             psOptions->bStats = true;
2800             psOptions->bApproxStats = false;
2801         }
2802         else if( EQUAL(papszArgv[i], "-approx_stats") )
2803         {
2804             psOptions->bStats = true;
2805             psOptions->bApproxStats = true;
2806         }
2807         else if( EQUAL(papszArgv[i], "-norat") )
2808         {
2809             psOptions->bNoRAT = true;
2810         }
2811         else if( i+1 < argc && EQUAL(papszArgv[i], "-oo") )
2812         {
2813             i++;
2814             if( psOptionsForBinary )
2815             {
2816                 psOptionsForBinary->papszOpenOptions =
2817                     CSLAddString( psOptionsForBinary->papszOpenOptions,
2818                                                 papszArgv[i] );
2819             }
2820         }
2821         else if( i+1 < argc && EQUAL(papszArgv[i],"-r") )
2822         {
2823             CPLFree(psOptions->pszResampling);
2824             psOptions->pszResampling = CPLStrdup(papszArgv[++i]);
2825         }
2826 
2827         else if( EQUAL(papszArgv[i],"-colorinterp") && papszArgv[i+1] )
2828         {
2829             ++i;
2830             CPLStringList aosList(CSLTokenizeString2(papszArgv[i], ",", 0));
2831             psOptions->nColorInterpSize = aosList.size();
2832             psOptions->panColorInterp = static_cast<int *>(
2833                   CPLRealloc(psOptions->panColorInterp,
2834                              psOptions->nColorInterpSize * sizeof(int)));
2835             for( int j = 0; j < aosList.size(); j++ )
2836             {
2837                 psOptions->panColorInterp[j] = GetColorInterp(aosList[j]);
2838             }
2839         }
2840 
2841         else if( STARTS_WITH_CI(papszArgv[i], "-colorinterp_") && papszArgv[i+1] )
2842         {
2843             int nIndex = atoi(papszArgv[i] + strlen("-colorinterp_"));
2844             if( nIndex <= 0 || nIndex > 65535 )
2845             {
2846                 CPLError(CE_Failure, CPLE_NotSupported,
2847                          "Invalid parameter name: %s", papszArgv[i]);
2848                 GDALTranslateOptionsFree(psOptions);
2849                 return nullptr;
2850             }
2851             nIndex --;
2852 
2853             if( nIndex >= psOptions->nColorInterpSize )
2854             {
2855                 psOptions->panColorInterp = static_cast<int *>(
2856                     CPLRealloc(psOptions->panColorInterp,
2857                                 (nIndex + 1) * sizeof(int)));
2858                 if( nIndex > psOptions->nColorInterpSize )
2859                 {
2860                     memset(psOptions->panColorInterp +
2861                                 psOptions->nColorInterpSize,
2862                            0xFF, // -1
2863                            sizeof(int) * (nIndex - psOptions->nColorInterpSize));
2864                 }
2865                 psOptions->nColorInterpSize = nIndex + 1;
2866             }
2867             ++i;
2868             psOptions->panColorInterp[nIndex] = GetColorInterp(papszArgv[i]);
2869         }
2870 
2871 
2872         // Undocumented option used by gdal_translate_fuzzer
2873         else if( i+1 < argc && EQUAL(papszArgv[i],"-limit_outsize") )
2874         {
2875             psOptions->nLimitOutSize = atoi(papszArgv[i+1]);
2876             i++;
2877         }
2878 
2879         else if( i+1 < argc && EQUAL(papszArgv[i], "-if") )
2880         {
2881             i++;
2882             if( psOptionsForBinary )
2883             {
2884                 if( GDALGetDriverByName(papszArgv[i]) == nullptr )
2885                 {
2886                     CPLError(CE_Warning, CPLE_AppDefined,
2887                              "%s is not a recognized driver", papszArgv[i]);
2888                 }
2889                 psOptionsForBinary->papszAllowInputDrivers = CSLAddString(
2890                     psOptionsForBinary->papszAllowInputDrivers, papszArgv[i] );
2891             }
2892         }
2893 
2894         else if (EQUAL(papszArgv[i], "-noxmp"))
2895         {
2896             psOptions->bNoXMP = true;
2897         }
2898 
2899 
2900         else if( papszArgv[i][0] == '-' )
2901         {
2902             CPLError(CE_Failure, CPLE_NotSupported,
2903                      "Unknown option name '%s'", papszArgv[i]);
2904             GDALTranslateOptionsFree(psOptions);
2905             return nullptr;
2906         }
2907         else if( !bGotSourceFilename )
2908         {
2909             bGotSourceFilename = true;
2910             if( psOptionsForBinary )
2911                 psOptionsForBinary->pszSource = CPLStrdup(papszArgv[i]);
2912         }
2913         else if( !bGotDestFilename )
2914         {
2915             bGotDestFilename = true;
2916             if( psOptionsForBinary )
2917                 psOptionsForBinary->pszDest = CPLStrdup(papszArgv[i]);
2918         }
2919         else
2920         {
2921             CPLError(CE_Failure, CPLE_NotSupported,
2922                      "Too many command options '%s'", papszArgv[i]);
2923             GDALTranslateOptionsFree(psOptions);
2924             return nullptr;
2925         }
2926     }
2927 
2928     if (psOptions->nGCPCount > 0 && psOptions->bNoGCP)
2929     {
2930         CPLError(CE_Failure, CPLE_IllegalArg,
2931                  "-nogcp and -gcp cannot be used as the same time" );
2932         GDALTranslateOptionsFree(psOptions);
2933         return nullptr;
2934     }
2935 
2936     if( bOutsideExplicitlySet &&
2937         psOptions->nOXSizePixel == 0 && psOptions->dfOXSizePct == 0.0 &&
2938         psOptions->nOYSizePixel == 0 && psOptions->dfOYSizePct == 0.0 )
2939     {
2940         CPLError(CE_Failure, CPLE_NotSupported,
2941                  "-outsize %d %d invalid.", psOptions->nOXSizePixel, psOptions->nOYSizePixel);
2942         GDALTranslateOptionsFree(psOptions);
2943         return nullptr;
2944     }
2945 
2946     if( psOptionsForBinary )
2947     {
2948         if( psOptions->pszFormat )
2949             psOptionsForBinary->pszFormat = CPLStrdup(psOptions->pszFormat);
2950     }
2951 
2952     return psOptions;
2953 }
2954 
2955 /************************************************************************/
2956 /*                        GDALTranslateOptionsFree()                    */
2957 /************************************************************************/
2958 
2959 /**
2960  * Frees the GDALTranslateOptions struct.
2961  *
2962  * @param psOptions the options struct for GDALTranslate().
2963  *
2964  * @since GDAL 2.1
2965  */
2966 
GDALTranslateOptionsFree(GDALTranslateOptions * psOptions)2967 void GDALTranslateOptionsFree(GDALTranslateOptions *psOptions)
2968 {
2969     if( psOptions == nullptr ) return;
2970 
2971     CPLFree(psOptions->pszFormat);
2972     CPLFree(psOptions->panBandList);
2973     CSLDestroy(psOptions->papszCreateOptions);
2974     CPLFree(psOptions->pasScaleParams);
2975     CPLFree(psOptions->padfExponent);
2976     CSLDestroy(psOptions->papszMetadataOptions);
2977     CPLFree(psOptions->pszOutputSRS);
2978     if( psOptions->nGCPCount )
2979         GDALDeinitGCPs(psOptions->nGCPCount, psOptions->pasGCPs);
2980     CPLFree(psOptions->pasGCPs);
2981     CPLFree(psOptions->pszResampling);
2982     CPLFree(psOptions->pszProjSRS);
2983     CPLFree(psOptions->panColorInterp);
2984 
2985     CPLFree(psOptions);
2986 }
2987 
2988 /************************************************************************/
2989 /*                 GDALTranslateOptionsSetProgress()                    */
2990 /************************************************************************/
2991 
2992 /**
2993  * Set a progress function.
2994  *
2995  * @param psOptions the options struct for GDALTranslate().
2996  * @param pfnProgress the progress callback.
2997  * @param pProgressData the user data for the progress callback.
2998  *
2999  * @since GDAL 2.1
3000  */
3001 
GDALTranslateOptionsSetProgress(GDALTranslateOptions * psOptions,GDALProgressFunc pfnProgress,void * pProgressData)3002 void GDALTranslateOptionsSetProgress( GDALTranslateOptions *psOptions,
3003                                       GDALProgressFunc pfnProgress, void *pProgressData )
3004 {
3005     psOptions->pfnProgress = pfnProgress;
3006     psOptions->pProgressData = pProgressData;
3007     if( pfnProgress == GDALTermProgress )
3008         psOptions->bQuiet = false;
3009 }
3010