1 /******************************************************************************
2  *
3  * Project:  DAAS driver
4  * Purpose:  DAAS driver
5  * Author:   Even Rouault, <even.rouault at spatialys.com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2018-2019, Airbus DS Intelligence
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "cpl_http.h"
30 #include "gdal_frmts.h"
31 #include "gdal_alg.h"
32 #include "gdal_priv.h"
33 #include "ogr_spatialref.h"
34 #include "gdal_mdreader.h"
35 #include "../mem/memdataset.h"
36 
37 #include "cpl_json.h"
38 
39 #include <algorithm>
40 #include <array>
41 #include <memory>
42 
43 constexpr int knMIN_BLOCKSIZE = 64;
44 constexpr int knDEFAULT_BLOCKSIZE = 512;
45 constexpr int knMAX_BLOCKSIZE = 8192;
46 
47 constexpr GUInt32 RETRY_PER_BAND = 1;
48 constexpr GUInt32 RETRY_SPATIAL_SPLIT = 2;
49 
50 // Let's limit to 100 MB uncompressed per request
51 constexpr int knDEFAULT_SERVER_BYTE_LIMIT = 100 * 1024 * 1024;
52 
53 constexpr int MAIN_MASK_BAND_NUMBER = 0;
54 
55 /************************************************************************/
56 /*                          GDALDAASBandDesc                            */
57 /************************************************************************/
58 
59 class GDALDAASBandDesc
60 {
61     public:
62         int       nIndex = 0;
63         GDALDataType eDT = GDT_Unknown; // as declared in the GetMetadata response bands[]
64         CPLString osName;
65         CPLString osDescription;
66         CPLString osColorInterp;
67         bool      bIsMask = false;
68 };
69 
70 /************************************************************************/
71 /*                          GDALDAASDataset                             */
72 /************************************************************************/
73 
74 class GDALDAASRasterBand;
75 
76 class GDALDAASDataset final: public GDALDataset
77 {
78     public:
79         enum class Format
80         {
81             RAW,
82             PNG,
83             JPEG,
84             JPEG2000,
85         };
86 
87     private:
88         friend class GDALDAASRasterBand;
89 
90         CPLString m_osGetMetadataURL;
91 
92         CPLString m_osAuthURL;
93         CPLString m_osAccessToken;
94         time_t    m_nExpirationTime = 0;
95         CPLString m_osXForwardUser;
96 
97         GDALDAASDataset* m_poParentDS = nullptr;
98         //int         m_iOvrLevel = 0;
99 
100         CPLString m_osWKT;
101         CPLString m_osSRSType;
102         CPLString m_osSRSValue;
103         bool      m_bGotGeoTransform = false;
104         std::array<double,6> m_adfGeoTransform{{ 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 }};
105         bool      m_bRequestInGeoreferencedCoordinates = false;
106         GDALDataType m_eDT = GDT_Unknown;
107         int          m_nActualBitDepth = 0;
108         bool         m_bHasNoData = false;
109         double       m_dfNoDataValue = 0.0;
110         CPLString    m_osGetBufferURL;
111         int          m_nBlockSize = knDEFAULT_BLOCKSIZE;
112         Format       m_eFormat = Format::RAW;
113         GIntBig      m_nServerByteLimit = knDEFAULT_SERVER_BYTE_LIMIT;
114         GDALRIOResampleAlg m_eCurrentResampleAlg = GRIORA_NearestNeighbour;
115 
116         int          m_nMainMaskBandIndex = 0;
117         CPLString    m_osMainMaskName;
118         GDALDAASRasterBand* m_poMaskBand = nullptr;
119         std::vector<GDALDAASBandDesc> m_aoBandDesc;
120 
121         int       m_nXOffAdvise = 0;
122         int       m_nYOffAdvise = 0;
123         int       m_nXSizeAdvise = 0;
124         int       m_nYSizeAdvise = 0;
125 
126         int       m_nXOffFetched = 0;
127         int       m_nYOffFetched = 0;
128         int       m_nXSizeFetched = 0;
129         int       m_nYSizeFetched = 0;
130 
131         std::vector<std::unique_ptr<GDALDAASDataset>> m_apoOverviewDS;
132 
133         char    **m_papszOpenOptions = nullptr;
134 
135         // Methods
136         GDALDAASDataset(GDALDAASDataset* poParentDS, int iOvrLevel);
137 
138         bool      Open( GDALOpenInfo* poOpenInfo );
139         bool      GetAuthorization();
140         bool      GetImageMetadata();
141         char**    GetHTTPOptions();
142         void      ReadSRS(const CPLJSONObject& oProperties);
143         void      ReadRPCs(const CPLJSONObject& oProperties);
144         bool      SetupServerSideReprojection(const char* pszTargetSRS);
145         void      InstantiateBands();
146 
147     public:
148         GDALDAASDataset();
149         ~GDALDAASDataset();
150 
151         static int Identify( GDALOpenInfo* poOpenInfo );
152         static GDALDataset* OpenStatic( GDALOpenInfo* poOpenInfo );
153 
154         CPLErr          GetGeoTransform(double *padfTransform) override;
GetSpatialRef() const155         const OGRSpatialReference* GetSpatialRef() const override {
156             return GetSpatialRefFromOldGetProjectionRef();
157         }
158         const char*     _GetProjectionRef() override;
159         CPLErr          IRasterIO(GDALRWFlag eRWFlag,
160                                       int nXOff, int nYOff,
161                                       int nXSize, int nYSize,
162                                       void *pData,
163                                       int nBufXSize, int nBufYSize,
164                                       GDALDataType eBufType,
165                                       int nBandCount, int* panBands,
166                                       GSpacing nPixelSpace,
167                                       GSpacing nLineSpace,
168                                       GSpacing nBandSpace,
169                                       GDALRasterIOExtraArg *psExtraArg) override;
170         CPLErr          AdviseRead (int nXOff, int nYOff,
171                                         int nXSize, int nYSize,
172                                         int /* nBufXSize */,
173                                         int /* nBufYSize */,
174                                         GDALDataType /* eBufType */,
175                                         int /*nBands*/, int* /*panBands*/,
176                                         char ** /* papszOptions */) override;
177         void            FlushCache() override;
178 };
179 
180 
181 /************************************************************************/
182 /*                         GDALDAASRasterBand                            */
183 /************************************************************************/
184 
185 class GDALDAASRasterBand final: public GDALRasterBand
186 {
187         friend class GDALDAASDataset;
188 
189         int                 m_nSrcIndex = 0;
190         GDALColorInterp     m_eColorInterp = GCI_Undefined;
191 
192         CPLErr          GetBlocks    (int nBlockXOff, int nBlockYOff,
193                                       int nXBlocks, int nYBlocks,
194                                       const std::vector<int>& anRequestedBands,
195                                       void* pBuffer);
196 
197         GUInt32          PrefetchBlocks(int nXOff, int nYOff,
198                                         int nXSize, int nYSize,
199                                         const std::vector<int>& anRequestedBands);
200 
201     public:
202         GDALDAASRasterBand( GDALDAASDataset* poDS, int nBand,
203                             const GDALDAASBandDesc& oBandDesc );
204 
205         CPLErr          IReadBlock( int nBlockXOff, int nBlockYOff,
206                                     void* pData) override;
207         CPLErr          IRasterIO(GDALRWFlag eRWFlag,
208                                       int nXOff, int nYOff,
209                                       int nXSize, int nYSize,
210                                       void *pData,
211                                       int nBufXSize, int nBufYSize,
212                                       GDALDataType eBufType,
213                                       GSpacing nPixelSpace,
214                                       GSpacing nLineSpace,
215                                       GDALRasterIOExtraArg *psExtraArg) override;
216         CPLErr          AdviseRead (int nXOff, int nYOff,
217                                         int nXSize, int nYSize,
218                                         int /* nBufXSize */,
219                                         int /* nBufYSize */,
220                                         GDALDataType /* eBufType */,
221                                         char ** /* papszOptions */) override;
222         double          GetNoDataValue(int* pbHasNoData) override;
223         GDALColorInterp GetColorInterpretation() override;
224         GDALRasterBand *GetMaskBand() override;
225         int             GetMaskFlags() override;
226         int             GetOverviewCount() override;
227         GDALRasterBand* GetOverview(int) override;
228 };
229 
230 /************************************************************************/
231 /*                          GDALDAASDataset()                           */
232 /************************************************************************/
233 
GDALDAASDataset()234 GDALDAASDataset::GDALDAASDataset() :
235     m_osAuthURL(CPLGetConfigOption("GDAL_DAAS_AUTH_URL",
236         "https://authenticate.geoapi-airbusds.com/auth/realms/IDP/protocol/openid-connect/token"))
237 {
238 }
239 
240 /************************************************************************/
241 /*                          GDALDAASDataset()                           */
242 /************************************************************************/
243 
GDALDAASDataset(GDALDAASDataset * poParentDS,int iOvrLevel)244 GDALDAASDataset::GDALDAASDataset(GDALDAASDataset* poParentDS,
245                                  int iOvrLevel) :
246     m_osGetMetadataURL(poParentDS->m_osGetMetadataURL),
247     m_osAuthURL(poParentDS->m_osAuthURL),
248     m_osAccessToken(CPLString()), // only used by parent
249     m_nExpirationTime(0), // only used by parent
250     m_osXForwardUser(CPLString()), // only used by parent
251     m_poParentDS(poParentDS),
252     //m_iOvrLevel(iOvrLevel),
253     m_osWKT(poParentDS->m_osWKT),
254     m_osSRSType(poParentDS->m_osSRSType),
255     m_osSRSValue(poParentDS->m_osSRSValue),
256     m_bGotGeoTransform(poParentDS->m_bGotGeoTransform),
257     m_bRequestInGeoreferencedCoordinates(poParentDS->m_bRequestInGeoreferencedCoordinates),
258     m_eDT(poParentDS->m_eDT),
259     m_nActualBitDepth(poParentDS->m_nActualBitDepth),
260     m_bHasNoData(poParentDS->m_bHasNoData),
261     m_dfNoDataValue(poParentDS->m_dfNoDataValue),
262     m_osGetBufferURL(poParentDS->m_osGetBufferURL),
263     m_eFormat(poParentDS->m_eFormat),
264     m_nServerByteLimit(poParentDS->m_nServerByteLimit),
265     m_nMainMaskBandIndex(poParentDS->m_nMainMaskBandIndex),
266     m_osMainMaskName(poParentDS->m_osMainMaskName),
267     m_poMaskBand(nullptr),
268     m_aoBandDesc(poParentDS->m_aoBandDesc)
269 {
270     nRasterXSize = m_poParentDS->nRasterXSize >> iOvrLevel;
271     nRasterYSize = m_poParentDS->nRasterYSize >> iOvrLevel;
272     m_adfGeoTransform[0] = m_poParentDS->m_adfGeoTransform[0];
273     m_adfGeoTransform[1] = m_poParentDS->m_adfGeoTransform[1] *
274                                     m_poParentDS->nRasterXSize / nRasterXSize;
275     m_adfGeoTransform[2] = m_poParentDS->m_adfGeoTransform[2];
276     m_adfGeoTransform[3] = m_poParentDS->m_adfGeoTransform[3];
277     m_adfGeoTransform[4] = m_poParentDS->m_adfGeoTransform[4];
278     m_adfGeoTransform[5] = m_poParentDS->m_adfGeoTransform[5] *
279                                     m_poParentDS->nRasterYSize / nRasterYSize;
280 
281     InstantiateBands();
282 
283     SetMetadata( m_poParentDS->GetMetadata() );
284     SetMetadata( m_poParentDS->GetMetadata("RPC"), "RPC" );
285 }
286 
287 /************************************************************************/
288 /*                         ~GDALDAASDataset()                            */
289 /************************************************************************/
290 
~GDALDAASDataset()291 GDALDAASDataset::~GDALDAASDataset()
292 {
293     if( m_poParentDS == nullptr )
294     {
295         char** papszOptions = nullptr;
296         papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT",
297                                     CPLSPrintf("%p", this));
298         CPLHTTPDestroyResult(CPLHTTPFetch( "", papszOptions));
299         CSLDestroy(papszOptions);
300     }
301 
302     delete m_poMaskBand;
303     CSLDestroy(m_papszOpenOptions);
304 }
305 
306 /************************************************************************/
307 /*                          InstantiateBands()                          */
308 /************************************************************************/
309 
InstantiateBands()310 void GDALDAASDataset::InstantiateBands()
311 {
312     for( int i = 0; i < static_cast<int>(m_aoBandDesc.size()); i++ )
313     {
314         GDALRasterBand* poBand = new GDALDAASRasterBand(this, i+1,
315                                                         m_aoBandDesc[i]);
316         SetBand( i+1 , poBand );
317     }
318 
319     if( !m_osMainMaskName.empty() )
320     {
321         GDALDAASBandDesc oDesc;
322         oDesc.nIndex = m_nMainMaskBandIndex;
323         oDesc.osName = m_osMainMaskName;
324         m_poMaskBand = new GDALDAASRasterBand(this, 0, oDesc);
325     }
326 
327     if( nBands > 1 )
328     {
329         // Hint for users of the driver
330         GDALDataset::SetMetadataItem(
331             "INTERLEAVE",
332             "PIXEL",
333             "IMAGE_STRUCTURE");
334     }
335 }
336 
337 /************************************************************************/
338 /*                            Identify()                                */
339 /************************************************************************/
340 
Identify(GDALOpenInfo * poOpenInfo)341 int GDALDAASDataset::Identify( GDALOpenInfo* poOpenInfo )
342 {
343     return STARTS_WITH_CI(poOpenInfo->pszFilename, "DAAS:");
344 }
345 
346 /************************************************************************/
347 /*                        GetGeoTransform()                             */
348 /************************************************************************/
349 
GetGeoTransform(double * padfTransform)350 CPLErr GDALDAASDataset::GetGeoTransform(double *padfTransform)
351 {
352     std::copy_n(m_adfGeoTransform.begin(), m_adfGeoTransform.size(),
353                 padfTransform);
354     return (m_bGotGeoTransform) ? CE_None : CE_Failure;
355 }
356 
357 /************************************************************************/
358 /*                        GetProjectionRef()                            */
359 /************************************************************************/
360 
_GetProjectionRef()361 const char* GDALDAASDataset::_GetProjectionRef()
362 {
363     return m_osWKT.c_str();
364 }
365 
366 /********************-****************************************************/
367 /*                             URLEscape()                              */
368 /************************************************************************/
369 
URLEscape(const CPLString & osStr)370 static CPLString URLEscape(const CPLString& osStr)
371 {
372     char* pszEscaped = CPLEscapeString(osStr.c_str(), -1, CPLES_URL);
373     CPLString osRet(pszEscaped);
374     CPLFree(pszEscaped);
375     return osRet;
376 }
377 
378 /************************************************************************/
379 /*                             GetHTTPOptions()                         */
380 /************************************************************************/
381 
GetHTTPOptions()382 char** GDALDAASDataset::GetHTTPOptions()
383 {
384     if( m_poParentDS )
385         return m_poParentDS->GetHTTPOptions();
386 
387     char** papszOptions = nullptr;
388     CPLString osHeaders;
389     if( !m_osAccessToken.empty() )
390     {
391         // Renew token if needed
392         if( m_nExpirationTime != 0 && time(nullptr) >= m_nExpirationTime )
393         {
394             GetAuthorization();
395         }
396         osHeaders += "Authorization: Bearer "  + m_osAccessToken;
397     }
398     else
399     {
400         const char* pszAuthorization =
401             CPLGetConfigOption("GDAL_DAAS_AUTHORIZATION", nullptr);
402         if( pszAuthorization )
403             osHeaders += pszAuthorization;
404     }
405     if( !m_osXForwardUser.empty() )
406     {
407         if( !osHeaders.empty() )
408             osHeaders += "\r\n";
409         osHeaders += "X-Forwarded-User: " + m_osXForwardUser;
410     }
411     if( !osHeaders.empty() )
412     {
413         papszOptions = CSLSetNameValue(papszOptions, "HEADERS",
414                                     osHeaders.c_str());
415     }
416     papszOptions = CSLSetNameValue(papszOptions, "PERSISTENT",
417                                    CPLSPrintf("%p", this));
418     // 30 minutes
419     papszOptions = CSLSetNameValue(papszOptions, "TIMEOUT", "1800");
420     return papszOptions;
421 }
422 
423 
424 
425 /************************************************************************/
426 /*                          DAASBackoffFactor()                         */
427 /************************************************************************/
428 
429 /* Add a small amount of random jitter to avoid cyclic server stampedes */
DAASBackoffFactor(double base)430 static double DAASBackoffFactor(double base)
431 {
432     // We don't need cryptographic quality randomness...
433     // coverity[dont_call]
434     return base + rand() * 0.5 / RAND_MAX;
435 }
436 
437 /************************************************************************/
438 /*                          DAAS_CPLHTTPFetch()                         */
439 /************************************************************************/
440 
441 static
DAAS_CPLHTTPFetch(const char * pszURL,char ** papszOptions)442 CPLHTTPResult* DAAS_CPLHTTPFetch(const char* pszURL, char** papszOptions)
443 {
444     CPLHTTPResult* psResult;
445     const int RETRY_COUNT = 4;
446     // coverity[tainted_data]
447     double dfRetryDelay = CPLAtof(CPLGetConfigOption(
448         "GDAL_DAAS_INITIAL_RETRY_DELAY", "1.0"));
449     for(int i=0; i <= RETRY_COUNT; i++)
450     {
451         psResult = CPLHTTPFetch(pszURL, papszOptions);
452         if( psResult == nullptr )
453             break;
454 
455         if (psResult->nDataLen != 0
456             && psResult->nStatus == 0
457             && psResult->pszErrBuf == nullptr)
458         {
459             /* got a valid response */
460             CPLErrorReset();
461             break;
462         }
463         else
464         {
465             const char* pszErrorText = psResult->pszErrBuf ?
466                                     psResult->pszErrBuf : "(null)";
467 
468             /* Get HTTP status code */
469             int nHTTPStatus = -1;
470             if( psResult->pszErrBuf != nullptr &&
471                 EQUALN(psResult->pszErrBuf, "HTTP error code : ",
472                        strlen("HTTP error code : ")) )
473             {
474                 nHTTPStatus = atoi(psResult->pszErrBuf +
475                                         strlen("HTTP error code : "));
476                 if( psResult->pabyData )
477                     pszErrorText = (const char*)psResult->pabyData;
478             }
479 
480             if( (nHTTPStatus == 500 ||
481                  (nHTTPStatus >= 502 && nHTTPStatus <= 504)) &&
482                  i < RETRY_COUNT )
483             {
484                 CPLError( CE_Warning, CPLE_FileIO,
485                           "Error when downloading %s,"
486                           "HTTP status=%d, retrying in %.2fs : %s",
487                           pszURL, nHTTPStatus, dfRetryDelay, pszErrorText);
488                 CPLHTTPDestroyResult(psResult);
489                 psResult = nullptr;
490 
491                 CPLSleep( dfRetryDelay );
492                 dfRetryDelay *= DAASBackoffFactor(4);
493             }
494             else
495             {
496                 break;
497             }
498         }
499     }
500 
501     return psResult;
502 }
503 
504 /************************************************************************/
505 /*                           GetAuthorization()                         */
506 /************************************************************************/
507 
GetAuthorization()508 bool GDALDAASDataset::GetAuthorization()
509 {
510     CPLString osClientId =
511         CSLFetchNameValueDef(m_papszOpenOptions, "CLIENT_ID",
512                              CPLGetConfigOption("GDAL_DAAS_CLIENT_ID", ""));
513     CPLString osAPIKey =
514         CSLFetchNameValueDef(m_papszOpenOptions, "API_KEY",
515                              CPLGetConfigOption("GDAL_DAAS_API_KEY", ""));
516     CPLString osAuthorization =
517         CSLFetchNameValueDef(m_papszOpenOptions, "ACCESS_TOKEN",
518                              CPLGetConfigOption("GDAL_DAAS_ACCESS_TOKEN", ""));
519     m_osXForwardUser =
520         CSLFetchNameValueDef(m_papszOpenOptions, "X_FORWARDED_USER",
521                         CPLGetConfigOption("GDAL_DAAS_X_FORWARDED_USER", ""));
522 
523     if( !osAuthorization.empty() )
524     {
525         if( !osClientId.empty() && !osAPIKey.empty() )
526         {
527             CPLError(CE_Warning, CPLE_AppDefined,
528                     "GDAL_DAAS_CLIENT_ID + GDAL_DAAS_API_KEY and "
529                     "GDAL_DAAS_ACCESS_TOKEN defined. Only the later taken into "
530                     "account");
531         }
532         m_osAccessToken = osAuthorization;
533         return true;
534     }
535 
536     if( osClientId.empty() && osAPIKey.empty() )
537     {
538         CPLDebug("DAAS", "Neither GDAL_DAAS_CLIENT_ID, GDAL_DAAS_API_KEY "
539                  "nor GDAL_DAAS_ACCESS_TOKEN is defined. Trying without "
540                  "authorization");
541         return true;
542     }
543 
544     if( osClientId.empty() )
545     {
546         CPLError(CE_Failure, CPLE_AppDefined,
547                  "GDAL_DAAS_API_KEY defined, but GDAL_DAAS_CLIENT_ID missing.");
548         return false;
549     }
550 
551     if( osAPIKey.empty() )
552     {
553         CPLError(CE_Failure, CPLE_AppDefined,
554                  "GDAL_DAAS_CLIENT_ID defined, but GDAL_DAAS_API_KEY missing.");
555         return false;
556     }
557 
558     CPLString osPostContent;
559     osPostContent += "client_id=" + URLEscape(osClientId);
560     osPostContent += "&apikey=" + URLEscape(osAPIKey);
561     osPostContent += "&grant_type=api_key";
562 
563     char** papszOptions = nullptr;
564     papszOptions = CSLSetNameValue(papszOptions, "POSTFIELDS",
565                                    osPostContent.c_str());
566     CPLString osHeaders("Content-Type: application/x-www-form-urlencoded");
567     papszOptions = CSLSetNameValue(papszOptions, "HEADERS", osHeaders.c_str());
568     // FIXME for server side: make sure certificates are valid
569     papszOptions = CSLSetNameValue(papszOptions, "UNSAFESSL", "YES");
570     CPLHTTPResult* psResult = DAAS_CPLHTTPFetch( m_osAuthURL, papszOptions);
571     CSLDestroy(papszOptions);
572 
573     if( psResult->pszErrBuf != nullptr )
574     {
575         CPLError( CE_Failure, CPLE_AppDefined,
576                   "Get request %s failed: %s",
577                   m_osAuthURL.c_str(),
578                   psResult->pabyData ? CPLSPrintf("%s: %s",
579                     psResult->pszErrBuf,
580                     reinterpret_cast<const char*>(psResult->pabyData )) :
581                   psResult->pszErrBuf );
582         CPLHTTPDestroyResult(psResult);
583         return false;
584     }
585 
586     if( psResult->pabyData == nullptr )
587     {
588         CPLError(CE_Failure, CPLE_AppDefined,
589                  "Authorization request failed: "
590                  "Empty content returned by server");
591         CPLHTTPDestroyResult(psResult);
592         return false;
593     }
594 
595     CPLString osAuthorizationResponse(
596                         reinterpret_cast<char*>(psResult->pabyData));
597     CPLHTTPDestroyResult(psResult);
598 
599     CPLJSONDocument oDoc;
600     if( !oDoc.LoadMemory(osAuthorizationResponse) )
601     {
602         CPLError(CE_Failure, CPLE_AppDefined,
603                  "Cannont parse GetAuthorization response");
604         return false;
605     }
606 
607     m_osAccessToken = oDoc.GetRoot().GetString("access_token");
608     if( m_osAccessToken.empty() )
609     {
610         CPLError(CE_Failure, CPLE_AppDefined, "Cannot retrieve access_token");
611         return false;
612     }
613 
614     int nExpiresIn = oDoc.GetRoot().GetInteger("expires_in");
615     if( nExpiresIn > 0 )
616     {
617         m_nExpirationTime = time(nullptr) + nExpiresIn - 60;
618     }
619 
620     return true;
621 }
622 
623 /************************************************************************/
624 /*                           GetObject()                                */
625 /************************************************************************/
626 
GetObject(CPLJSONObject & oContainer,const char * pszPath,CPLJSONObject::Type eExpectedType,const char * pszExpectedType,bool bVerboseError,bool & bError)627 static CPLJSONObject GetObject(CPLJSONObject& oContainer, const char* pszPath,
628                                CPLJSONObject::Type eExpectedType,
629                                const char* pszExpectedType,
630                                bool bVerboseError, bool& bError)
631 {
632     CPLJSONObject oObj = oContainer.GetObj(pszPath);
633     if( !oObj.IsValid() )
634     {
635         if( bVerboseError )
636         {
637             CPLError(CE_Failure, CPLE_AppDefined, "%s missing", pszPath);
638         }
639         bError = true;
640         oObj.Deinit();
641         return oObj;
642     }
643     if( oObj.GetType() != eExpectedType)
644     {
645         CPLError(CE_Failure, CPLE_AppDefined,
646                     "%s not %s", pszPath, pszExpectedType);
647         bError = true;
648         oObj.Deinit();
649         return oObj;
650     }
651     return oObj;
652 }
653 
654 /************************************************************************/
655 /*                          GetInteger()                                */
656 /************************************************************************/
657 
GetInteger(CPLJSONObject & oContainer,const char * pszPath,bool bVerboseError,bool & bError)658 static int GetInteger(CPLJSONObject& oContainer, const char* pszPath,
659                       bool bVerboseError, bool& bError)
660 {
661     CPLJSONObject oObj = GetObject(oContainer, pszPath,
662                                    CPLJSONObject::Type::Integer, "an integer",
663                                    bVerboseError, bError);
664     if( !oObj.IsValid() )
665     {
666         return 0;
667     }
668     return oObj.ToInteger();
669 }
670 
671 /************************************************************************/
672 /*                          GetDouble()                                */
673 /************************************************************************/
674 
GetDouble(CPLJSONObject & oContainer,const char * pszPath,bool bVerboseError,bool & bError)675 static double GetDouble(CPLJSONObject& oContainer, const char* pszPath,
676                         bool bVerboseError, bool& bError)
677 {
678     CPLJSONObject oObj = oContainer.GetObj(pszPath);
679     if( !oObj.IsValid() )
680     {
681         if( bVerboseError )
682         {
683             CPLError(CE_Failure, CPLE_AppDefined, "%s missing", pszPath);
684         }
685         bError = true;
686         return 0.0;
687     }
688     if( oObj.GetType() != CPLJSONObject::Type::Integer &&
689         oObj.GetType() != CPLJSONObject::Type::Double)
690     {
691         CPLError(CE_Failure, CPLE_AppDefined,
692                     "%s not a double", pszPath);
693         bError = true;
694         return 0.0;
695     }
696     return oObj.ToDouble();
697 }
698 
699 /************************************************************************/
700 /*                          GetString()                                 */
701 /************************************************************************/
702 
GetString(CPLJSONObject & oContainer,const char * pszPath,bool bVerboseError,bool & bError)703 static CPLString GetString(CPLJSONObject& oContainer, const char* pszPath,
704                            bool bVerboseError, bool& bError)
705 {
706     CPLJSONObject oObj = GetObject(oContainer, pszPath,
707                                    CPLJSONObject::Type::String, "a string",
708                                    bVerboseError, bError);
709     if( !oObj.IsValid() )
710     {
711         return CPLString();
712     }
713     return oObj.ToString();
714 }
715 
716 /************************************************************************/
717 /*                     GetGDALDataTypeFromDAASPixelType()               */
718 /************************************************************************/
719 
GetGDALDataTypeFromDAASPixelType(const CPLString & osPixelType)720 static GDALDataType GetGDALDataTypeFromDAASPixelType(
721                                                 const CPLString& osPixelType)
722 {
723     const struct {
724         const char* pszName;
725         GDALDataType eDT;
726     } asDataTypes[] = {
727         { "Byte",    GDT_Byte },
728         { "UInt16",  GDT_UInt16 },
729         { "Int16",   GDT_Int16 },
730         { "UInt32",  GDT_UInt32 },
731         { "Int32",   GDT_Int32 },
732         { "Float32", GDT_Float32 },
733         { "Float64", GDT_Float64 },
734     };
735     for( size_t i = 0; i < CPL_ARRAYSIZE(asDataTypes); ++i )
736     {
737         if( osPixelType == asDataTypes[i].pszName )
738         {
739             return asDataTypes[i].eDT;
740         }
741     }
742     return GDT_Unknown;
743 }
744 
745 /************************************************************************/
746 /*                         GetImageMetadata()                           */
747 /************************************************************************/
748 
GetImageMetadata()749 bool GDALDAASDataset::GetImageMetadata()
750 {
751     char** papszOptions = GetHTTPOptions();
752     CPLHTTPResult* psResult = DAAS_CPLHTTPFetch(m_osGetMetadataURL,
753                                                 papszOptions);
754     CSLDestroy(papszOptions);
755     if( psResult == nullptr )
756         return false;
757 
758     if( psResult->pszErrBuf != nullptr )
759     {
760         CPLError( CE_Failure, CPLE_AppDefined,
761                   "Get request %s failed: %s",
762                   m_osGetMetadataURL.c_str(),
763                   psResult->pabyData ? CPLSPrintf("%s: %s",
764                     psResult->pszErrBuf,
765                     reinterpret_cast<const char*>(psResult->pabyData )) :
766                   psResult->pszErrBuf );
767         CPLHTTPDestroyResult(psResult);
768         return false;
769     }
770 
771     if( psResult->pabyData == nullptr )
772     {
773         CPLError(CE_Failure, CPLE_AppDefined,
774                  "Get request %s failed: "
775                  "Empty content returned by server",
776                  m_osGetMetadataURL.c_str());
777         CPLHTTPDestroyResult(psResult);
778         return false;
779     }
780 
781     CPLString osResponse(reinterpret_cast<char*>(psResult->pabyData));
782     CPLHTTPDestroyResult(psResult);
783 
784     CPLJSONDocument oDoc;
785     CPLDebug("DAAS", "%s", osResponse.c_str());
786     if( !oDoc.LoadMemory(osResponse) )
787     {
788         CPLError(CE_Failure, CPLE_AppDefined,
789                  "Cannont parse GetImageMetadata response");
790         return false;
791     }
792 
793     CPLJSONObject oProperties = oDoc.GetRoot().GetObj(
794         "response/payload/payload/imageMetadata/properties");
795     if( !oProperties.IsValid() )
796     {
797         oProperties = oDoc.GetRoot().GetObj("properties");
798         if( !oProperties.IsValid() )
799         {
800             CPLError(CE_Failure, CPLE_AppDefined,
801                     "Cannont find response/payload/payload/imageMetadata/"
802                     "properties nor properties in GetImageMetadata response");
803             return false;
804         }
805     }
806 
807     bool bError = false;
808     nRasterXSize = GetInteger(oProperties, "width", true, bError);
809     nRasterYSize = GetInteger(oProperties, "height", true, bError);
810     if( !bError && !GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) )
811     {
812         bError = true;
813     }
814 
815     bool bIgnoredError = false;
816 
817     m_nActualBitDepth = GetInteger(oProperties, "actualBitDepth", false,
818                                    bIgnoredError);
819 
820     bool bNoDataError = false;
821     m_dfNoDataValue = GetDouble(oProperties, "noDataValue", false,
822                                 bNoDataError);
823     m_bHasNoData = !bNoDataError;
824 
825     CPLJSONObject oGetBufferObj = oProperties.GetObj("_links/getBuffer");
826     if( !oGetBufferObj.IsValid() )
827     {
828         CPLError(CE_Failure, CPLE_AppDefined, "%s missing",
829                     "_links/getBuffer");
830         bError = true;
831     }
832     CPLJSONObject oGetBufferDict;
833     oGetBufferDict.Deinit();
834     if( oGetBufferObj.GetType() == CPLJSONObject::Type::Array )
835     {
836         auto array = oGetBufferObj.ToArray();
837         if( array.Size() > 0 )
838         {
839             oGetBufferDict = array[0];
840         }
841     }
842     else if( oGetBufferObj.GetType() == CPLJSONObject::Type::Object )
843     {
844         oGetBufferDict = oGetBufferObj;
845     }
846     if( !oGetBufferDict.IsValid() )
847     {
848         CPLError(CE_Failure, CPLE_AppDefined, "%s missing",
849                     "_links/getBuffer/href");
850         bError = true;
851     }
852     else
853     {
854         m_osGetBufferURL = GetString(oGetBufferDict, "href", true,
855                                         bError);
856     }
857 
858 #ifndef REMOVE_THAT_LEGACY_CODE
859     if( !STARTS_WITH_CI(m_osGetMetadataURL, "https://192.168.") &&
860         !STARTS_WITH_CI(m_osGetMetadataURL, "http://192.168.") &&
861         STARTS_WITH_CI(m_osGetBufferURL, "http://192.168.") )
862     {
863         size_t nPosDaas = m_osGetMetadataURL.find("/daas/");
864         size_t nPosImages = m_osGetMetadataURL.find("/images/");
865         if( nPosDaas != std::string::npos && nPosImages != std::string::npos )
866         {
867             m_osGetBufferURL = m_osGetMetadataURL.substr(0, nPosDaas) +
868                 "/daas/images/" +
869                 m_osGetMetadataURL.substr(nPosImages + strlen("/images/")) +
870                 "/buffer";
871         }
872     }
873 #endif
874 
875     CPLJSONArray oGTArray = oProperties.GetArray("geotransform");
876     if( oGTArray.IsValid() && oGTArray.Size() == 6 )
877     {
878         m_bGotGeoTransform = true;
879         for( int i = 0; i < 6; i++ )
880         {
881             m_adfGeoTransform[i] = oGTArray[i].ToDouble();
882         }
883     }
884 
885     CPLJSONArray oBandArray = oProperties.GetArray("bands");
886     if( !oBandArray.IsValid() || oBandArray.Size() == 0 )
887     {
888         CPLError(CE_Failure, CPLE_AppDefined,
889                 "Missing or empty bands array");
890         bError = true;
891     }
892     else
893     {
894         for( int i = 0; i < oBandArray.Size(); ++i )
895         {
896             CPLJSONObject oBandObj = oBandArray[i];
897             if( oBandObj.GetType() == CPLJSONObject::Type::Object )
898             {
899                 GDALDAASBandDesc oDesc;
900                 oDesc.nIndex = i + 1;
901                 oDesc.osName = GetString(oBandObj, "name", true, bError);
902                 oDesc.osDescription = GetString(oBandObj, "description",
903                                                 false, bIgnoredError);
904                 oDesc.osColorInterp = GetString(oBandObj, "colorInterpretation",
905                                                 false, bIgnoredError);
906                 oDesc.bIsMask = oBandObj.GetBool("isMask");
907 
908                 const CPLString osPixelType(GetString(oBandObj, "pixelType", true, bError));
909                 oDesc.eDT = GetGDALDataTypeFromDAASPixelType(osPixelType);
910                 if( oDesc.eDT == GDT_Unknown )
911                 {
912                     CPLError(CE_Failure, CPLE_NotSupported,
913                             "Unsupported value pixelType = '%s'", osPixelType.c_str());
914                     bError = true;
915                 }
916                 if( i == 0 )
917                 {
918                     m_eDT = oDesc.eDT;
919                 }
920 
921                 if( !CPLFetchBool( m_papszOpenOptions, "MASKS", true ) &&
922                     oDesc.bIsMask )
923                 {
924                     continue;
925                 }
926                 if( oDesc.osColorInterp == "MAIN_MASK" &&
927                     m_osMainMaskName.empty() )
928                 {
929                     m_nMainMaskBandIndex = i + 1;
930                     m_osMainMaskName = oDesc.osName;
931                 }
932                 else
933                 {
934                     m_aoBandDesc.push_back(oDesc);
935                 }
936             }
937             else
938             {
939                 CPLError(CE_Failure, CPLE_AppDefined,
940                         "Invalid bands[] element");
941                 bError = true;
942             }
943         }
944     }
945 
946     ReadSRS(oProperties);
947 
948     ReadRPCs(oProperties);
949 
950     // Collect other metadata
951     for( const auto& oObj: oProperties.GetChildren() )
952     {
953         const CPLString& osName(oObj.GetName());
954         const auto& oType(oObj.GetType());
955         if( osName != "aoiFactor" &&
956             osName != "crsCode" &&
957             osName != "nbBands" &&
958             osName != "nbBits" &&
959             osName != "nBits" &&
960             osName != "actualBitDepth" &&
961             osName != "width" &&
962             osName != "height" &&
963             osName != "noDataValue" &&
964             osName != "step" &&
965             osName != "pixelType" &&
966             oObj.IsValid() &&
967             oType != CPLJSONObject::Type::Null &&
968             oType != CPLJSONObject::Type::Array &&
969             oType != CPLJSONObject::Type::Object )
970         {
971             SetMetadataItem( osName.c_str(), oObj.ToString().c_str() );
972         }
973     }
974 
975     // Metadata for IMAGERY domain
976     CPLString osAcquisitionDate(
977         GetString(oProperties, "acquisitionDate", false, bIgnoredError));
978     if( !osAcquisitionDate.empty() )
979     {
980         int iYear = 0;
981         int iMonth = 0;
982         int iDay = 0;
983         int iHours = 0;
984         int iMin = 0;
985         int iSec = 0;
986         const int r = sscanf (osAcquisitionDate.c_str(),
987                               "%d-%d-%dT%d:%d:%d.%*dZ",
988                               &iYear, &iMonth, &iDay, &iHours, &iMin, &iSec);
989         if( r == 6 )
990         {
991             SetMetadataItem( MD_NAME_ACQDATETIME,
992                              CPLSPrintf("%04d-%02d-%02d %02d:%02d:%02d",
993                                         iYear, iMonth, iDay,
994                                         iHours, iMin, iSec),
995                              MD_DOMAIN_IMAGERY );
996         }
997     }
998 
999     bIgnoredError = false;
1000     double dfCloudCover = GetDouble(
1001         oProperties, "cloudCover", false, bIgnoredError);
1002     if( !bIgnoredError )
1003     {
1004         SetMetadataItem( MD_NAME_CLOUDCOVER,
1005                          CPLSPrintf("%.2f", dfCloudCover),
1006                          MD_DOMAIN_IMAGERY );
1007     }
1008 
1009     CPLString osSatellite(
1010         GetString(oProperties, "satellite", false, bIgnoredError));
1011     if( !osSatellite.empty() )
1012     {
1013         SetMetadataItem( MD_NAME_SATELLITE, osSatellite.c_str(),
1014                          MD_DOMAIN_IMAGERY );
1015     }
1016 
1017     return !bError;
1018 }
1019 
1020 
1021 /************************************************************************/
1022 /*                            ReadSRS()                                 */
1023 /************************************************************************/
1024 
ReadSRS(const CPLJSONObject & oProperties)1025 void GDALDAASDataset::ReadSRS(const CPLJSONObject& oProperties)
1026 {
1027     CPLJSONArray oSRSArray = oProperties.GetArray("srsExpression/names");
1028     if( oSRSArray.IsValid() )
1029     {
1030         for( int i = 0; i < oSRSArray.Size(); ++i )
1031         {
1032             CPLJSONObject oSRSObj = oSRSArray[i];
1033             if( oSRSObj.GetType() == CPLJSONObject::Type::Object )
1034             {
1035                 bool bError = false;
1036                 CPLString osType( GetString(oSRSObj, "type", true, bError) );
1037                 CPLString osValue( GetString(oSRSObj, "value", true, bError) );
1038                 // Use urn in priority
1039                 if( osType == "urn" && !osValue.empty() )
1040                 {
1041                     m_osSRSType = osType;
1042                     m_osSRSValue = osValue;
1043                 }
1044                 // Use proj4 if urn not already set
1045                 else if( osType == "proj4" && !osValue.empty() &&
1046                          m_osSRSType != "urn" )
1047                 {
1048                     m_osSRSType = osType;
1049                     m_osSRSValue = osValue;
1050                 }
1051                 // If no SRS set, take the first one
1052                 else if( m_osSRSValue.empty() && !osType.empty() &&
1053                          !osValue.empty() )
1054                 {
1055                     m_osSRSType = osType;
1056                     m_osSRSValue = osValue;
1057                 }
1058             }
1059         }
1060     }
1061     else
1062     {
1063         auto osCrsCode = oProperties.GetString("crsCode");
1064         if( !osCrsCode.empty() )
1065         {
1066             m_osSRSType = "urn";
1067             m_osSRSValue = osCrsCode;
1068         }
1069     }
1070 
1071     if( m_osSRSType == "urn" || m_osSRSType == "proj4" )
1072     {
1073         OGRSpatialReference oSRS;
1074         if( oSRS.SetFromUserInput(m_osSRSValue) == OGRERR_NONE )
1075         {
1076             OGR_SRSNode *poGEOGCS = oSRS.GetAttrNode("GEOGCS");
1077             if( poGEOGCS != nullptr )
1078                 poGEOGCS->StripNodes("AXIS");
1079 
1080             OGR_SRSNode *poPROJCS = oSRS.GetAttrNode("PROJCS");
1081             if (poPROJCS != nullptr && oSRS.EPSGTreatsAsNorthingEasting())
1082                 poPROJCS->StripNodes("AXIS");
1083 
1084             char* pszWKT = nullptr;
1085             oSRS.exportToWkt(&pszWKT);
1086             if( pszWKT )
1087                 m_osWKT = pszWKT;
1088             CPLFree(pszWKT);
1089         }
1090     }
1091 }
1092 
1093 /************************************************************************/
1094 /*                            ReadRPCs()                                */
1095 /************************************************************************/
1096 
ReadRPCs(const CPLJSONObject & oProperties)1097 void GDALDAASDataset::ReadRPCs(const CPLJSONObject& oProperties)
1098 {
1099     CPLJSONObject oRPC = oProperties.GetObj("rpc");
1100     if( oRPC.IsValid() )
1101     {
1102         bool bRPCError = false;
1103         CPLStringList aoRPC;
1104         const struct {
1105             const char* pszJsonName;
1106             const char* pszGDALName;
1107         } asRPCSingleValues[] = {
1108             { "errBias", RPC_ERR_BIAS},
1109             { "errRand", RPC_ERR_RAND},
1110             { "sampOff", RPC_SAMP_OFF },
1111             { "lineOff", RPC_LINE_OFF },
1112             { "latOff",  RPC_LAT_OFF },
1113             { "longOff", RPC_LONG_OFF },
1114             { "heightOff", RPC_HEIGHT_OFF },
1115             { "lineScale", RPC_LINE_SCALE },
1116             { "sampScale", RPC_SAMP_SCALE },
1117             { "latScale", RPC_LAT_SCALE },
1118             { "longScale", RPC_LONG_SCALE },
1119             { "heightScale", RPC_HEIGHT_SCALE },
1120         };
1121         for( size_t i = 0; i < CPL_ARRAYSIZE(asRPCSingleValues); ++i )
1122         {
1123             bool bRPCErrorTmp = false;
1124             const bool bVerboseError =
1125                 !(strcmp(asRPCSingleValues[i].pszGDALName, RPC_ERR_BIAS) == 0 ||
1126                   strcmp(asRPCSingleValues[i].pszGDALName, RPC_ERR_RAND) == 0);
1127             double dfRPCVal = GetDouble(oRPC, asRPCSingleValues[i].pszJsonName, bVerboseError, bRPCErrorTmp);
1128             if (bRPCErrorTmp)
1129             {
1130                 if (bVerboseError)
1131                 {
1132                     bRPCError = true;
1133                 }
1134                 continue;
1135             }
1136             aoRPC.SetNameValue(asRPCSingleValues[i].pszGDALName, CPLSPrintf("%.18g", dfRPCVal));
1137         }
1138 
1139         const struct {
1140             const char* pszJsonName;
1141             const char* pszGDALName;
1142         } asRPCArrayValues[] = {
1143             { "lineNumCoeff", RPC_LINE_NUM_COEFF },
1144             { "lineDenCoeff", RPC_LINE_DEN_COEFF },
1145             { "sampNumCoeff", RPC_SAMP_NUM_COEFF },
1146             { "sampDenCoeff", RPC_SAMP_DEN_COEFF },
1147         };
1148         for( size_t i = 0; i < CPL_ARRAYSIZE(asRPCArrayValues); ++i )
1149         {
1150             CPLJSONArray oRPCArray =
1151                 oRPC.GetArray(asRPCArrayValues[i].pszJsonName);
1152             if( oRPCArray.IsValid() && oRPCArray.Size() == 20 )
1153             {
1154                 CPLString osVal;
1155                 for( int j = 0; j < 20; j++ )
1156                 {
1157                     if( j > 0 )
1158                         osVal += " ";
1159                     osVal += CPLSPrintf("%.18g", oRPCArray[j].ToDouble());
1160                 }
1161                 aoRPC.SetNameValue(asRPCArrayValues[i].pszGDALName,
1162                                    osVal.c_str());
1163             }
1164             else
1165             {
1166                 CPLError(CE_Failure, CPLE_AppDefined,
1167                          "Cannot find %s", asRPCArrayValues[i].pszJsonName);
1168             }
1169         }
1170         if( !bRPCError )
1171         {
1172             SetMetadata(aoRPC.List(), "RPC");
1173         }
1174     }
1175 }
1176 
1177 /************************************************************************/
1178 /*                      SetupServerSideReprojection()                   */
1179 /************************************************************************/
1180 
SetupServerSideReprojection(const char * pszTargetSRS)1181 bool GDALDAASDataset::SetupServerSideReprojection(const char* pszTargetSRS)
1182 {
1183     if( m_osWKT.empty() || !m_bGotGeoTransform )
1184     {
1185         CPLError(CE_Failure, CPLE_AppDefined,
1186                     "TARGET_SRS is specified, but projection and/or "
1187                     "geotransform are missing in image metadata");
1188         return false;
1189     }
1190 
1191     OGRSpatialReference oSRS;
1192     if( oSRS.SetFromUserInput(pszTargetSRS) != OGRERR_NONE )
1193     {
1194         CPLError(CE_Failure, CPLE_AppDefined,
1195                     "Invalid TARGET_SRS value");
1196         return false;
1197     }
1198 
1199     // Check that we can find the EPSG code as we will need to
1200     // provide as a urn to getBuffer
1201     const char* pszAuthorityCode = oSRS.GetAuthorityCode(nullptr);
1202     const char* pszAuthorityName = oSRS.GetAuthorityName(nullptr);
1203     if( pszAuthorityName == nullptr || !EQUAL(pszAuthorityName, "EPSG") ||
1204         pszAuthorityCode == nullptr )
1205     {
1206         CPLError(CE_Failure, CPLE_AppDefined,
1207                     "TARGET_SRS cannot be identified to a EPSG code");
1208         return false;
1209     }
1210 
1211     CPLString osTargetEPSGCode = CPLString("epsg:") + pszAuthorityCode;
1212 
1213     char* pszWKT = nullptr;
1214     oSRS.exportToWkt(&pszWKT);
1215     char** papszTO = CSLSetNameValue( nullptr, "DST_SRS", pszWKT );
1216     CPLString osTargetWKT = pszWKT;
1217     CPLFree(pszWKT);
1218 
1219     void* hTransformArg =
1220             GDALCreateGenImgProjTransformer2( this, nullptr, papszTO );
1221     if( hTransformArg == nullptr )
1222     {
1223         CSLDestroy(papszTO);
1224         return false;
1225     }
1226 
1227     GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg;
1228     double adfGeoTransform[6];
1229     double adfExtent[4];
1230     int    nXSize, nYSize;
1231 
1232     if ( GDALSuggestedWarpOutput2( this,
1233                                 psInfo->pfnTransform, hTransformArg,
1234                                 adfGeoTransform,
1235                                 &nXSize, &nYSize,
1236                                 adfExtent, 0 ) != CE_None )
1237     {
1238         CPLError(CE_Failure, CPLE_AppDefined,
1239                     "Cannot find extent in specified TARGET_SRS");
1240         CSLDestroy(papszTO);
1241         GDALDestroyGenImgProjTransformer( hTransformArg );
1242         return false;
1243     }
1244 
1245     GDALDestroyGenImgProjTransformer( hTransformArg );
1246 
1247     std::copy_n(adfGeoTransform, 6, m_adfGeoTransform.begin());
1248     m_bRequestInGeoreferencedCoordinates = true;
1249     m_osSRSType = "epsg";
1250     m_osSRSValue = osTargetEPSGCode;
1251     m_osWKT = osTargetWKT;
1252     nRasterXSize = nXSize;
1253     nRasterYSize = nYSize;
1254     return true;
1255 }
1256 
1257 /************************************************************************/
1258 /*                              Open()                                  */
1259 /************************************************************************/
1260 
Open(GDALOpenInfo * poOpenInfo)1261 bool GDALDAASDataset::Open( GDALOpenInfo* poOpenInfo )
1262 {
1263     m_papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
1264     m_osGetMetadataURL =
1265         CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "GET_METADATA_URL",
1266                              poOpenInfo->pszFilename + strlen("DAAS:"));
1267     if( m_osGetMetadataURL.empty() )
1268     {
1269         CPLError(CE_Failure, CPLE_AppDefined,
1270                  "GET_METADATA_URL is missing");
1271         return false;
1272     }
1273     m_nBlockSize = std::max(knMIN_BLOCKSIZE, std::min(knMAX_BLOCKSIZE,
1274         atoi(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
1275                                   "BLOCK_SIZE",
1276                                   CPLSPrintf("%d", m_nBlockSize)))));
1277     m_nServerByteLimit = atoi(CPLGetConfigOption("GDAL_DAAS_SERVER_BYTE_LIMIT",
1278                             CPLSPrintf("%d", knDEFAULT_SERVER_BYTE_LIMIT)));
1279 
1280     if( CPLTestBool(CPLGetConfigOption("GDAL_DAAS_PERFORM_AUTH", "YES")) &&
1281         !GetAuthorization() )
1282         return false;
1283     if( !GetImageMetadata() )
1284         return false;
1285 
1286     const char* pszFormat = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
1287                                                  "PIXEL_ENCODING",
1288                                                  "AUTO");
1289     if( EQUAL(pszFormat, "AUTO") )
1290     {
1291         if( (m_aoBandDesc.size() == 1 || m_aoBandDesc.size() == 3 ||
1292              m_aoBandDesc.size() == 4) && m_eDT == GDT_Byte )
1293         {
1294             m_eFormat = Format::PNG;
1295         }
1296         else
1297         {
1298             m_eFormat = Format::RAW;
1299         }
1300     }
1301     else if( EQUAL(pszFormat, "RAW") )
1302     {
1303         m_eFormat = Format::RAW;
1304     }
1305     else if( EQUAL(pszFormat, "PNG") )
1306     {
1307         if( (m_aoBandDesc.size() == 1 || m_aoBandDesc.size() == 3 ||
1308              m_aoBandDesc.size() == 4) && m_eDT == GDT_Byte )
1309         {
1310             m_eFormat = Format::PNG;
1311         }
1312         else
1313         {
1314             CPLError(CE_Warning, CPLE_AppDefined,
1315                      "PNG only supported for 1, 3 or 4-band Byte dataset. "
1316                      "Falling back to RAW");
1317             m_eFormat = Format::RAW;
1318         }
1319     }
1320     else if( EQUAL(pszFormat, "JPEG") )
1321     {
1322         if( (m_aoBandDesc.size() == 1 || m_aoBandDesc.size() == 3) &&
1323             m_eDT == GDT_Byte )
1324         {
1325             m_eFormat = Format::JPEG;
1326         }
1327         else
1328         {
1329             CPLError(CE_Warning, CPLE_AppDefined,
1330                      "JPEG only supported for 1 or 3-band Byte dataset. "
1331                      "Falling back to RAW");
1332             m_eFormat = Format::RAW;
1333         }
1334     }
1335     else if( EQUAL(pszFormat, "JPEG2000") )
1336     {
1337         if( m_eDT != GDT_Float32 && m_eDT != GDT_Float64 )
1338         {
1339             m_eFormat = Format::JPEG2000;
1340         }
1341         else
1342         {
1343             CPLError(CE_Warning, CPLE_AppDefined,
1344                      "JPEG2000 only supported for integer datatype dataset. "
1345                      "Falling back to RAW");
1346             m_eFormat = Format::RAW;
1347         }
1348     }
1349     else
1350     {
1351         CPLError(CE_Failure, CPLE_NotSupported,
1352                  "Unsupported PIXEL_ENCODING=%s", pszFormat);
1353         return false;
1354     }
1355 
1356     const char* pszTargetSRS = CSLFetchNameValue(poOpenInfo->papszOpenOptions,
1357                                                  "TARGET_SRS");
1358     if( pszTargetSRS )
1359     {
1360         if( !SetupServerSideReprojection(pszTargetSRS) )
1361         {
1362             return false;
1363         }
1364     }
1365 
1366     InstantiateBands();
1367 
1368     // Instantiate overviews
1369     int iOvr = 0;
1370     while( (nRasterXSize >> iOvr) > 256 || (nRasterYSize >> iOvr) > 256 )
1371     {
1372         iOvr ++;
1373         if( (nRasterXSize >> iOvr) == 0 ||
1374             (nRasterYSize >> iOvr) == 0 )
1375         {
1376             break;
1377         }
1378         m_apoOverviewDS.push_back(
1379             std::unique_ptr<GDALDAASDataset>(new GDALDAASDataset(this, iOvr)));
1380     }
1381 
1382     return true;
1383 }
1384 
OpenStatic(GDALOpenInfo * poOpenInfo)1385 GDALDataset* GDALDAASDataset::OpenStatic( GDALOpenInfo* poOpenInfo )
1386 {
1387     if( !Identify(poOpenInfo) )
1388         return nullptr;
1389 
1390     std::unique_ptr<GDALDAASDataset> poDS =
1391         std::unique_ptr<GDALDAASDataset>(new GDALDAASDataset());
1392     if( !poDS->Open(poOpenInfo) )
1393         return nullptr;
1394     return poDS.release();
1395 }
1396 
1397 /************************************************************************/
1398 /*                       GDALDAASRasterBand()                          */
1399 /************************************************************************/
1400 
GDALDAASRasterBand(GDALDAASDataset * poDSIn,int nBandIn,const GDALDAASBandDesc & oBandDesc)1401 GDALDAASRasterBand::GDALDAASRasterBand( GDALDAASDataset* poDSIn, int nBandIn,
1402                                         const GDALDAASBandDesc& oBandDesc )
1403 {
1404     poDS = poDSIn;
1405     nBand = nBandIn;
1406     eDataType = poDSIn->m_eDT;
1407     nRasterXSize = poDSIn->GetRasterXSize();
1408     nRasterYSize = poDSIn->GetRasterYSize();
1409     nBlockXSize = poDSIn->m_nBlockSize;
1410     nBlockYSize = poDSIn->m_nBlockSize;
1411     m_nSrcIndex = oBandDesc.nIndex;
1412 
1413     SetDescription( oBandDesc.osName );
1414     if( !oBandDesc.osDescription.empty() )
1415     {
1416         SetMetadataItem("DESCRIPTION", oBandDesc.osDescription );
1417     }
1418 
1419     const struct {
1420         const char* pszName;
1421         GDALColorInterp eColorInterp;
1422     } asColorInterpretations[] = {
1423         { "RED",         GCI_RedBand },
1424         { "GREEN",       GCI_GreenBand },
1425         { "BLUE",        GCI_BlueBand },
1426         { "GRAY",        GCI_GrayIndex },
1427         { "ALPHA",       GCI_AlphaBand },
1428         { "UNDEFINED",   GCI_Undefined },
1429     };
1430     for( size_t i = 0; i < CPL_ARRAYSIZE(asColorInterpretations); ++i )
1431     {
1432         if( EQUAL(oBandDesc.osColorInterp, asColorInterpretations[i].pszName ) )
1433         {
1434             m_eColorInterp = asColorInterpretations[i].eColorInterp;
1435             break;
1436         }
1437     }
1438     if( !oBandDesc.osColorInterp.empty() &&
1439         !EQUAL(oBandDesc.osColorInterp, "UNDEFINED") &&
1440         m_eColorInterp != GCI_Undefined )
1441     {
1442         SetMetadataItem("COLOR_INTERPRETATION", oBandDesc.osColorInterp );
1443     }
1444 
1445     if( poDSIn->m_nActualBitDepth != 0 && poDSIn->m_nActualBitDepth != 8 &&
1446         poDSIn->m_nActualBitDepth != 16 && poDSIn->m_nActualBitDepth != 32 &&
1447         poDSIn->m_nActualBitDepth != 64 )
1448     {
1449         SetMetadataItem("NBITS",
1450                         CPLSPrintf("%d", poDSIn->m_nActualBitDepth),
1451                         "IMAGE_STRUCTURE");
1452     }
1453 }
1454 
1455 /************************************************************************/
1456 /*                         GetNoDataValue()                             */
1457 /************************************************************************/
1458 
GetNoDataValue(int * pbHasNoData)1459 double GDALDAASRasterBand::GetNoDataValue(int* pbHasNoData)
1460 {
1461     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1462     if( poGDS->m_bHasNoData )
1463     {
1464         if( pbHasNoData )
1465             *pbHasNoData = true;
1466         return poGDS->m_dfNoDataValue;
1467     }
1468     if( pbHasNoData )
1469         *pbHasNoData = false;
1470     return 0.0;
1471 }
1472 
1473 /************************************************************************/
1474 /*                       GetColorInterpretation()                       */
1475 /************************************************************************/
1476 
GetColorInterpretation()1477 GDALColorInterp GDALDAASRasterBand::GetColorInterpretation()
1478 {
1479     return m_eColorInterp;
1480 }
1481 
1482 /************************************************************************/
1483 /*                            GetMaskBand()                             */
1484 /************************************************************************/
1485 
GetMaskBand()1486 GDALRasterBand *GDALDAASRasterBand::GetMaskBand()
1487 {
1488     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1489     if( poGDS->m_poMaskBand )
1490         return poGDS->m_poMaskBand;
1491     return GDALRasterBand::GetMaskBand();
1492 }
1493 
1494 /************************************************************************/
1495 /*                           GetMaskFlags()                             */
1496 /************************************************************************/
1497 
GetMaskFlags()1498 int GDALDAASRasterBand::GetMaskFlags()
1499 {
1500     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1501     if( poGDS->m_poMaskBand )
1502         return GMF_PER_DATASET;
1503     return GDALRasterBand::GetMaskFlags();
1504 }
1505 
1506 /************************************************************************/
1507 /*                      CanSpatiallySplit()                             */
1508 /************************************************************************/
1509 
CanSpatiallySplit(GUInt32 nRetryFlags,int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,int nBlockXSize,int nBlockYSize,GSpacing nPixelSpace,GSpacing nLineSpace,int & nXOff1,int & nYOff1,int & nXSize1,int & nYSize1,int & nXOff2,int & nYOff2,int & nXSize2,int & nYSize2,GSpacing & nDataShift2)1510 static bool CanSpatiallySplit(GUInt32 nRetryFlags,
1511                               int nXOff, int nYOff,
1512                               int nXSize, int nYSize,
1513                               int nBufXSize, int nBufYSize,
1514                               int nBlockXSize, int nBlockYSize,
1515                               GSpacing nPixelSpace,
1516                               GSpacing nLineSpace,
1517                               int& nXOff1, int& nYOff1,
1518                               int& nXSize1, int& nYSize1,
1519                               int& nXOff2, int& nYOff2,
1520                               int& nXSize2, int& nYSize2,
1521                               GSpacing& nDataShift2)
1522 {
1523     if( (nRetryFlags & RETRY_SPATIAL_SPLIT) &&
1524         nXSize == nBufXSize && nYSize == nBufYSize && nYSize > nBlockYSize )
1525     {
1526         int nHalf = std::max(nBlockYSize,
1527                              ((nYSize / 2 ) / nBlockYSize) * nBlockYSize);
1528         nXOff1 = nXOff;
1529         nYOff1 = nYOff;
1530         nXSize1 = nXSize;
1531         nYSize1 = nHalf;
1532         nXOff2 = nXOff;
1533         nYOff2 = nYOff + nHalf;
1534         nXSize2 = nXSize;
1535         nYSize2 = nYSize - nHalf;
1536         nDataShift2 = nHalf * nLineSpace;
1537         return true;
1538     }
1539     else if( (nRetryFlags & RETRY_SPATIAL_SPLIT) &&
1540         nXSize == nBufXSize && nYSize == nBufYSize && nXSize > nBlockXSize )
1541     {
1542         int nHalf = std::max(nBlockXSize,
1543                              ((nXSize / 2 ) / nBlockXSize) * nBlockXSize);
1544         nXOff1 = nXOff;
1545         nYOff1 = nYOff;
1546         nXSize1 = nHalf;
1547         nYSize1 = nYSize;
1548         nXOff2 = nXOff + nHalf;
1549         nYOff2 = nYOff;
1550         nXSize2 = nXSize - nHalf;
1551         nYSize2 = nYSize;
1552         nDataShift2 = nHalf * nPixelSpace;
1553         return true;
1554     }
1555     return false;
1556 }
1557 
1558 /************************************************************************/
1559 /*                           IRasterIO()                                */
1560 /************************************************************************/
1561 
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)1562 CPLErr GDALDAASDataset::IRasterIO(GDALRWFlag eRWFlag,
1563                                       int nXOff, int nYOff,
1564                                       int nXSize, int nYSize,
1565                                       void *pData,
1566                                       int nBufXSize, int nBufYSize,
1567                                       GDALDataType eBufType,
1568                                       int nBandCount, int* panBandMap,
1569                                       GSpacing nPixelSpace,
1570                                       GSpacing nLineSpace,
1571                                       GSpacing nBandSpace,
1572                                       GDALRasterIOExtraArg *psExtraArg)
1573 {
1574     m_eCurrentResampleAlg = psExtraArg->eResampleAlg;
1575 
1576 /* ==================================================================== */
1577 /*      Do we have overviews that would be appropriate to satisfy       */
1578 /*      this request?                                                   */
1579 /* ==================================================================== */
1580     if( (nBufXSize < nXSize || nBufYSize < nYSize)
1581         && GetRasterBand(1)->GetOverviewCount() > 0 && eRWFlag == GF_Read )
1582     {
1583         GDALRasterIOExtraArg sExtraArg;
1584         GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
1585 
1586         const int nOverview =
1587             GDALBandGetBestOverviewLevel2( GetRasterBand(1),
1588                                             nXOff, nYOff, nXSize, nYSize,
1589                                            nBufXSize, nBufYSize, &sExtraArg );
1590         if (nOverview >= 0)
1591         {
1592             GDALRasterBand* poOverviewBand =
1593                         GetRasterBand(1)->GetOverview(nOverview);
1594             if (poOverviewBand == nullptr ||
1595                 poOverviewBand->GetDataset() == nullptr)
1596             {
1597                 return CE_Failure;
1598             }
1599 
1600             return poOverviewBand->GetDataset()->RasterIO(
1601                 eRWFlag, nXOff, nYOff, nXSize, nYSize,
1602                 pData, nBufXSize, nBufYSize, eBufType,
1603                 nBandCount, panBandMap,
1604                 nPixelSpace, nLineSpace, nBandSpace, &sExtraArg );
1605         }
1606     }
1607 
1608     GDALDAASRasterBand* poBand =
1609         cpl::down_cast<GDALDAASRasterBand*>(GetRasterBand(1));
1610 
1611     std::vector<int> anRequestedBands;
1612     if( m_poMaskBand)
1613         anRequestedBands.push_back(0);
1614     for( int i = 1; i <= GetRasterCount(); i++ )
1615         anRequestedBands.push_back(i);
1616     GUInt32 nRetryFlags = poBand->PrefetchBlocks(
1617                                 nXOff, nYOff, nXSize, nYSize,
1618                                 anRequestedBands);
1619     int nBlockXSize, nBlockYSize;
1620     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
1621     int nXOff1 = 0;
1622     int nYOff1 = 0;
1623     int nXSize1 = 0;
1624     int nYSize1 = 0;
1625     int nXOff2 = 0;
1626     int nYOff2 = 0;
1627     int nXSize2 = 0;
1628     int nYSize2 = 0;
1629     GSpacing nDataShift2 = 0;
1630     if( CanSpatiallySplit(nRetryFlags, nXOff, nYOff, nXSize, nYSize,
1631                         nBufXSize, nBufYSize,
1632                         nBlockXSize, nBlockYSize,
1633                         nPixelSpace, nLineSpace,
1634                         nXOff1, nYOff1,
1635                         nXSize1, nYSize1,
1636                         nXOff2, nYOff2,
1637                         nXSize2, nYSize2,
1638                         nDataShift2) )
1639     {
1640         GDALRasterIOExtraArg sExtraArg;
1641         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1642 
1643         CPLErr eErr = IRasterIO(eRWFlag, nXOff1, nYOff1,
1644                                 nXSize1, nYSize1,
1645                                 pData,
1646                                 nXSize1, nYSize1,
1647                                 eBufType,
1648                                 nBandCount, panBandMap,
1649                                 nPixelSpace, nLineSpace, nBandSpace,
1650                                 &sExtraArg);
1651         if( eErr == CE_None )
1652         {
1653             eErr = IRasterIO(eRWFlag,
1654                                 nXOff2, nYOff2,
1655                                 nXSize2, nYSize2,
1656                                 static_cast<GByte*>(pData) + nDataShift2,
1657                                 nXSize2, nYSize2,
1658                                 eBufType,
1659                                 nBandCount, panBandMap,
1660                                 nPixelSpace, nLineSpace, nBandSpace,
1661                                 &sExtraArg);
1662         }
1663         return eErr;
1664     }
1665     else if( (nRetryFlags & RETRY_PER_BAND) && nBands > 1 )
1666     {
1667         for( int iBand = 1; iBand <= nBands; iBand++ )
1668         {
1669             poBand =
1670                 cpl::down_cast<GDALDAASRasterBand*>(GetRasterBand(iBand));
1671             CPL_IGNORE_RET_VAL(poBand->PrefetchBlocks(
1672                                     nXOff, nYOff, nXSize, nYSize,
1673                                     std::vector<int>{iBand}));
1674         }
1675     }
1676 
1677     return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1678                                   pData, nBufXSize, nBufYSize,
1679                                   eBufType,
1680                                   nBandCount, panBandMap,
1681                                   nPixelSpace, nLineSpace, nBandSpace,
1682                                   psExtraArg);
1683 }
1684 
1685 /************************************************************************/
1686 /*                          AdviseRead()                                */
1687 /************************************************************************/
1688 
AdviseRead(int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,GDALDataType,int,int *,char **)1689 CPLErr GDALDAASDataset::AdviseRead (int nXOff, int nYOff,
1690                                    int nXSize, int nYSize,
1691                                    int nBufXSize,
1692                                    int nBufYSize,
1693                                    GDALDataType /* eBufType */,
1694                                    int /*nBands*/, int* /*panBands*/,
1695                                    char ** /* papszOptions */)
1696 {
1697     if( nXSize == nBufXSize && nYSize == nBufYSize )
1698     {
1699         m_nXOffAdvise = nXOff;
1700         m_nYOffAdvise = nYOff;
1701         m_nXSizeAdvise = nXSize;
1702         m_nYSizeAdvise = nYSize;
1703     }
1704     return CE_None;
1705 }
1706 
1707 /************************************************************************/
1708 /*                          FlushCache()                                */
1709 /************************************************************************/
1710 
FlushCache()1711 void GDALDAASDataset::FlushCache ()
1712 {
1713     GDALDataset::FlushCache();
1714     m_nXOffFetched = 0;
1715     m_nYOffFetched = 0;
1716     m_nXSizeFetched = 0;
1717     m_nYSizeFetched = 0;
1718 }
1719 
1720 /************************************************************************/
1721 /*                           GetOverviewCount()                         */
1722 /************************************************************************/
1723 
GetOverviewCount()1724 int GDALDAASRasterBand::GetOverviewCount()
1725 {
1726     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1727     return static_cast<int>(poGDS->m_apoOverviewDS.size());
1728 }
1729 
1730 /************************************************************************/
1731 /*                              GetOverview()                           */
1732 /************************************************************************/
1733 
GetOverview(int iIndex)1734 GDALRasterBand* GDALDAASRasterBand::GetOverview(int iIndex)
1735 {
1736     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1737     if( iIndex >= 0 &&
1738         iIndex < static_cast<int>(poGDS->m_apoOverviewDS.size()) )
1739     {
1740         return poGDS->m_apoOverviewDS[iIndex]->GetRasterBand(nBand);
1741     }
1742     return nullptr;
1743 }
1744 
1745 /************************************************************************/
1746 /*                          IReadBlock()                                */
1747 /************************************************************************/
1748 
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)1749 CPLErr GDALDAASRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1750                                         void* pImage)
1751 {
1752     return GetBlocks(nBlockXOff, nBlockYOff, 1, 1,
1753                      std::vector<int>{nBand}, pImage);
1754 }
1755 
1756 /************************************************************************/
1757 /*                           IRasterIO()                                */
1758 /************************************************************************/
1759 
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace,GDALRasterIOExtraArg * psExtraArg)1760 CPLErr GDALDAASRasterBand::IRasterIO(GDALRWFlag eRWFlag,
1761                                       int nXOff, int nYOff,
1762                                       int nXSize, int nYSize,
1763                                       void *pData,
1764                                       int nBufXSize, int nBufYSize,
1765                                       GDALDataType eBufType,
1766                                       GSpacing nPixelSpace,
1767                                       GSpacing nLineSpace,
1768                                       GDALRasterIOExtraArg *psExtraArg)
1769 {
1770     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1771 
1772     poGDS->m_eCurrentResampleAlg = psExtraArg->eResampleAlg;
1773 
1774 /* ==================================================================== */
1775 /*      Do we have overviews that would be appropriate to satisfy       */
1776 /*      this request?                                                   */
1777 /* ==================================================================== */
1778     if( (nBufXSize < nXSize || nBufYSize < nYSize)
1779         && GetOverviewCount() > 0 && eRWFlag == GF_Read )
1780     {
1781         GDALRasterIOExtraArg sExtraArg;
1782         GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
1783 
1784         const int nOverview =
1785             GDALBandGetBestOverviewLevel2( this, nXOff, nYOff, nXSize, nYSize,
1786                                            nBufXSize, nBufYSize, &sExtraArg );
1787         if (nOverview >= 0)
1788         {
1789             GDALRasterBand* poOverviewBand = GetOverview(nOverview);
1790             if (poOverviewBand == nullptr)
1791                 return CE_Failure;
1792 
1793             return poOverviewBand->RasterIO(
1794                 eRWFlag, nXOff, nYOff, nXSize, nYSize,
1795                 pData, nBufXSize, nBufYSize, eBufType,
1796                 nPixelSpace, nLineSpace, &sExtraArg );
1797         }
1798     }
1799 
1800     std::vector<int> anRequestedBands;
1801     if( poGDS->m_poMaskBand)
1802         anRequestedBands.push_back(0);
1803     for( int i = 1; i <= poGDS->GetRasterCount(); i++ )
1804         anRequestedBands.push_back(i);
1805     GUInt32 nRetryFlags = PrefetchBlocks(
1806         nXOff, nYOff, nXSize, nYSize, anRequestedBands);
1807     int nXOff1 = 0;
1808     int nYOff1 = 0;
1809     int nXSize1 = 0;
1810     int nYSize1 = 0;
1811     int nXOff2 = 0;
1812     int nYOff2 = 0;
1813     int nXSize2 = 0;
1814     int nYSize2 = 0;
1815     GSpacing nDataShift2 = 0;
1816     if( CanSpatiallySplit(nRetryFlags, nXOff, nYOff, nXSize, nYSize,
1817                           nBufXSize, nBufYSize,
1818                           nBlockXSize, nBlockYSize,
1819                           nPixelSpace, nLineSpace,
1820                           nXOff1, nYOff1,
1821                           nXSize1, nYSize1,
1822                           nXOff2, nYOff2,
1823                           nXSize2, nYSize2,
1824                           nDataShift2) )
1825     {
1826         GDALRasterIOExtraArg sExtraArg;
1827         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1828 
1829         CPLErr eErr = IRasterIO(eRWFlag, nXOff1, nYOff1,
1830                                 nXSize1, nYSize1,
1831                                 pData,
1832                                 nXSize1, nYSize1,
1833                                 eBufType,
1834                                 nPixelSpace, nLineSpace,
1835                                 &sExtraArg);
1836         if( eErr == CE_None )
1837         {
1838             eErr = IRasterIO(eRWFlag,
1839                                 nXOff2, nYOff2,
1840                                 nXSize2, nYSize2,
1841                                 static_cast<GByte*>(pData) + nDataShift2,
1842                                 nXSize2, nYSize2,
1843                                 eBufType,
1844                                 nPixelSpace, nLineSpace,
1845                                 &sExtraArg);
1846         }
1847         return eErr;
1848     }
1849     else if( (nRetryFlags & RETRY_PER_BAND) && poGDS->nBands > 1 )
1850     {
1851         CPL_IGNORE_RET_VAL(PrefetchBlocks(
1852             nXOff, nYOff, nXSize, nYSize, std::vector<int>{nBand}));
1853     }
1854 
1855     return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1856                                      pData, nBufXSize, nBufYSize,
1857                                      eBufType,
1858                                      nPixelSpace, nLineSpace,
1859                                      psExtraArg);
1860 }
1861 
1862 /************************************************************************/
1863 /*                          AdviseRead()                                */
1864 /************************************************************************/
1865 
AdviseRead(int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,GDALDataType,char **)1866 CPLErr GDALDAASRasterBand::AdviseRead (int nXOff, int nYOff,
1867                                         int nXSize, int nYSize,
1868                                         int nBufXSize,
1869                                         int nBufYSize,
1870                                         GDALDataType /* eBufType */,
1871                                         char ** /* papszOptions */)
1872 {
1873     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1874     if( nXSize == nBufXSize && nYSize == nBufYSize )
1875     {
1876         poGDS->m_nXOffAdvise = nXOff;
1877         poGDS->m_nYOffAdvise = nYOff;
1878         poGDS->m_nXSizeAdvise = nXSize;
1879         poGDS->m_nYSizeAdvise = nYSize;
1880     }
1881     return CE_None;
1882 }
1883 
1884 /************************************************************************/
1885 /*                          PrefetchBlocks()                            */
1886 /************************************************************************/
1887 
1888 // Return or'ed flags among 0, RETRY_PER_BAND, RETRY_SPATIAL_SPLIT if the user
1889 // should try to split the request in smaller chunks
1890 
PrefetchBlocks(int nXOff,int nYOff,int nXSize,int nYSize,const std::vector<int> & anRequestedBands)1891 GUInt32 GDALDAASRasterBand::PrefetchBlocks(int nXOff, int nYOff,
1892                                            int nXSize, int nYSize,
1893                                            const std::vector<int>& anRequestedBands)
1894 {
1895     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
1896 
1897     if( anRequestedBands.size() > 1 )
1898     {
1899         if( poGDS->m_nXOffFetched == nXOff &&
1900             poGDS->m_nYOffFetched == nYOff &&
1901             poGDS->m_nXSizeFetched == nXSize &&
1902             poGDS->m_nYSizeFetched == nYSize )
1903         {
1904             return 0;
1905         }
1906         poGDS->m_nXOffFetched = nXOff;
1907         poGDS->m_nYOffFetched = nYOff;
1908         poGDS->m_nXSizeFetched = nXSize;
1909         poGDS->m_nYSizeFetched = nYSize;
1910     }
1911 
1912     int nBlockXOff = nXOff / nBlockXSize;
1913     int nBlockYOff = nYOff / nBlockYSize;
1914     int nXBlocks = (nXOff + nXSize - 1) / nBlockXSize - nBlockXOff + 1;
1915     int nYBlocks = (nYOff + nYSize - 1) / nBlockYSize - nBlockYOff + 1;
1916 
1917     int nTotalDataTypeSize = 0;
1918     const int nQueriedBands = static_cast<int>(anRequestedBands.size());
1919     for( int i = 0; i < nQueriedBands; i++ )
1920     {
1921         const int iBand = anRequestedBands[i];
1922         if( iBand > 0 && iBand <= poGDS->GetRasterCount() )
1923         {
1924             nTotalDataTypeSize += GDALGetDataTypeSizeBytes(
1925                     poGDS->GetRasterBand(iBand)->GetRasterDataType());
1926         }
1927         else
1928         {
1929             nTotalDataTypeSize += GDALGetDataTypeSizeBytes(
1930                     poGDS->m_poMaskBand->GetRasterDataType());
1931         }
1932     }
1933 
1934     // If AdviseRead() was called before, and the current requested area is
1935     // in it, check if we can prefetch the whole advised area
1936     const GIntBig nCacheMax = GDALGetCacheMax64()/2;
1937     if( poGDS->m_nXSizeAdvise > 0 &&
1938         nXOff >= poGDS->m_nXOffAdvise &&
1939         nYOff >= poGDS->m_nYOffAdvise &&
1940         nXOff + nXSize <= poGDS->m_nXOffAdvise + poGDS->m_nXSizeAdvise &&
1941         nYOff + nYSize <= poGDS->m_nYOffAdvise + poGDS->m_nYSizeAdvise )
1942     {
1943         int nBlockXOffAdvise = poGDS->m_nXOffAdvise / nBlockXSize;
1944         int nBlockYOffAdvise = poGDS->m_nYOffAdvise / nBlockYSize;
1945         int nXBlocksAdvise = (poGDS->m_nXOffAdvise +
1946             poGDS->m_nXSizeAdvise - 1) / nBlockXSize - nBlockXOffAdvise + 1;
1947         int nYBlocksAdvise = (poGDS->m_nYOffAdvise +
1948             poGDS->m_nYSizeAdvise - 1) / nBlockYSize - nBlockYOffAdvise + 1;
1949         const GIntBig nUncompressedSize =
1950             static_cast<GIntBig>(nXBlocksAdvise) * nYBlocksAdvise *
1951                         nBlockXSize * nBlockYSize * nTotalDataTypeSize;
1952         if( nUncompressedSize <= nCacheMax &&
1953             nUncompressedSize <= poGDS->m_nServerByteLimit )
1954         {
1955             CPLDebug("DAAS", "Using advise read");
1956             nBlockXOff = nBlockXOffAdvise;
1957             nBlockYOff = nBlockYOffAdvise;
1958             nXBlocks = nXBlocksAdvise;
1959             nYBlocks = nYBlocksAdvise;
1960             if( anRequestedBands.size() > 1 )
1961             {
1962                 poGDS->m_nXOffAdvise = 0;
1963                 poGDS->m_nYOffAdvise = 0;
1964                 poGDS->m_nXSizeAdvise = 0;
1965                 poGDS->m_nYSizeAdvise = 0;
1966             }
1967         }
1968     }
1969 
1970     // Check the number of already cached blocks, and remove fully
1971     // cached lines at the top of the area of interest from the queried
1972     // blocks
1973     int nBlocksCached = 0;
1974     int nBlocksCachedForThisBand = 0;
1975     bool bAllLineCached = true;
1976     for( int iYBlock = 0; iYBlock < nYBlocks; )
1977     {
1978         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1979         {
1980             for( int i = 0; i < nQueriedBands; i++ )
1981             {
1982                 const int iBand = anRequestedBands[i];
1983                 GDALRasterBlock* poBlock = nullptr;
1984                 GDALDAASRasterBand* poIterBand;
1985                 if( iBand > 0 && iBand <= poGDS->GetRasterCount() )
1986                     poIterBand = reinterpret_cast<GDALDAASRasterBand*>(
1987                                                     poGDS->GetRasterBand(iBand));
1988                 else
1989                     poIterBand = poGDS->m_poMaskBand;
1990 
1991                 poBlock = poIterBand->TryGetLockedBlockRef(
1992                     nBlockXOff + iXBlock, nBlockYOff + iYBlock);
1993                 if (poBlock != nullptr)
1994                 {
1995                     nBlocksCached ++;
1996                     if( iBand == nBand )
1997                         nBlocksCachedForThisBand ++;
1998                     poBlock->DropLock();
1999                     continue;
2000                 }
2001                 else
2002                 {
2003                     bAllLineCached = false;
2004                 }
2005             }
2006         }
2007 
2008         if( bAllLineCached )
2009         {
2010             nBlocksCached -= nXBlocks * nQueriedBands;
2011             nBlocksCachedForThisBand -= nXBlocks;
2012             nBlockYOff ++;
2013             nYBlocks --;
2014         }
2015         else
2016         {
2017             iYBlock ++;
2018         }
2019     }
2020 
2021     if( nXBlocks > 0 && nYBlocks > 0 )
2022     {
2023         bool bMustReturn = false;
2024         GUInt32 nRetryFlags = 0;
2025 
2026         // Get the blocks if the number of already cached blocks is lesser
2027         // than 25% of the to be queried blocks
2028         if( nBlocksCached > (nQueriedBands * nXBlocks * nYBlocks) / 4 )
2029         {
2030             if( nBlocksCachedForThisBand <= (nXBlocks * nYBlocks) / 4 )
2031             {
2032                 nRetryFlags |= RETRY_PER_BAND;
2033             }
2034             else
2035             {
2036                 bMustReturn = true;
2037             }
2038         }
2039 
2040         // Make sure that we have enough cache (with a margin of 50%)
2041         // and the number of queried pixels isn't too big w.r.t server
2042         // limit
2043         const GIntBig nUncompressedSize =
2044             static_cast<GIntBig>(nXBlocks) * nYBlocks *
2045                         nBlockXSize * nBlockYSize * nTotalDataTypeSize;
2046         if( nUncompressedSize > nCacheMax ||
2047             nUncompressedSize > poGDS->m_nServerByteLimit )
2048         {
2049             if( anRequestedBands.size() > 1 && poGDS->GetRasterCount() > 1 )
2050             {
2051                 const int nThisDTSize = GDALGetDataTypeSizeBytes(eDataType);
2052                 const GIntBig nUncompressedSizeThisBand =
2053                     static_cast<GIntBig>(nXBlocks) * nYBlocks *
2054                             nBlockXSize * nBlockYSize * nThisDTSize;
2055                 if( nUncompressedSizeThisBand <= poGDS->m_nServerByteLimit &&
2056                     nUncompressedSizeThisBand <= nCacheMax )
2057                 {
2058                     nRetryFlags |= RETRY_PER_BAND;
2059                 }
2060             }
2061             if( nXBlocks > 1 || nYBlocks > 1 )
2062             {
2063                 nRetryFlags |= RETRY_SPATIAL_SPLIT;
2064             }
2065             return nRetryFlags;
2066         }
2067         if( bMustReturn )
2068             return nRetryFlags;
2069 
2070         GetBlocks(nBlockXOff, nBlockYOff, nXBlocks, nYBlocks,
2071                   anRequestedBands, nullptr);
2072     }
2073 
2074     return 0;
2075 }
2076 
2077 /************************************************************************/
2078 /*                           GetBlocks()                                */
2079 /************************************************************************/
2080 
GetBlocks(int nBlockXOff,int nBlockYOff,int nXBlocks,int nYBlocks,const std::vector<int> & anRequestedBands,void * pDstBuffer)2081 CPLErr GDALDAASRasterBand::GetBlocks(int nBlockXOff, int nBlockYOff,
2082                                      int nXBlocks, int nYBlocks,
2083                                      const std::vector<int>& anRequestedBands,
2084                                      void* pDstBuffer)
2085 {
2086     GDALDAASDataset* poGDS = reinterpret_cast<GDALDAASDataset*>(poDS);
2087 
2088     CPLAssert( !anRequestedBands.empty() );
2089     if( pDstBuffer )
2090     {
2091         CPLAssert( nXBlocks == 1 && nYBlocks == 1 && anRequestedBands.size() == 1 );
2092     }
2093 
2094     // Detect if there is a mix of non-mask and mask bands
2095     if( anRequestedBands.size() > 1 )
2096     {
2097         std::vector<int> anNonMasks;
2098         std::vector<int> anMasks;
2099         for( auto& iBand: anRequestedBands )
2100         {
2101             if( iBand == MAIN_MASK_BAND_NUMBER || poGDS->m_aoBandDesc[iBand-1].bIsMask )
2102                 anMasks.push_back(iBand);
2103             else
2104                 anNonMasks.push_back(iBand);
2105         }
2106         if( !anNonMasks.empty() && !anMasks.empty() )
2107         {
2108             return
2109                 GetBlocks(nBlockXOff, nBlockYOff, nXBlocks, nYBlocks,
2110                           anNonMasks, nullptr) == CE_None &&
2111                 GetBlocks(nBlockXOff, nBlockYOff, nXBlocks, nYBlocks,
2112                           anMasks, nullptr) == CE_None ? CE_None : CE_Failure;
2113         }
2114     }
2115 
2116     char** papszOptions = poGDS->GetHTTPOptions();
2117 
2118     CPLString osHeaders = CSLFetchNameValueDef(papszOptions, "HEADERS", "");
2119     if( !osHeaders.empty() )
2120         osHeaders += "\r\n";
2121     osHeaders += "Content-Type: application/json";
2122     osHeaders += "\r\n";
2123     CPLString osDataContentType("application/octet-stream");
2124     GDALDAASDataset::Format eRequestFormat(GDALDAASDataset::Format::RAW);
2125     if( poGDS->m_eFormat == GDALDAASDataset::Format::PNG &&
2126         (anRequestedBands.size() == 1 || anRequestedBands.size() == 3 ||
2127          anRequestedBands.size() == 4 ) )
2128     {
2129         eRequestFormat = poGDS->m_eFormat;
2130         osDataContentType = "image/png";
2131     }
2132     else if( poGDS->m_eFormat == GDALDAASDataset::Format::JPEG &&
2133             (anRequestedBands.size() == 1 || anRequestedBands.size() == 3) )
2134     {
2135         eRequestFormat = poGDS->m_eFormat;
2136         osDataContentType = "image/jpeg";
2137     }
2138     else if( poGDS->m_eFormat == GDALDAASDataset::Format::JPEG2000 )
2139     {
2140         eRequestFormat = poGDS->m_eFormat;
2141         osDataContentType = "image/jp2";
2142     }
2143     osHeaders += "Accept: " + osDataContentType;
2144     papszOptions = CSLSetNameValue(papszOptions, "HEADERS", osHeaders);
2145 
2146     // Build request JSon document
2147     CPLJSONDocument oDoc;
2148     CPLJSONObject oBBox;
2149 
2150     if( poGDS->m_bRequestInGeoreferencedCoordinates )
2151     {
2152         CPLJSONObject oSRS;
2153         oSRS.Add("type", poGDS->m_osSRSType);
2154         oSRS.Add("value", poGDS->m_osSRSValue);
2155         oBBox.Add("srs", oSRS);
2156     }
2157     else
2158     {
2159         CPLJSONObject oSRS;
2160         oSRS.Add("type", "image");
2161         oBBox.Add("srs", oSRS);
2162     }
2163 
2164     const int nMainXSize = poGDS->m_poParentDS ?
2165                         poGDS->m_poParentDS->GetRasterXSize() : nRasterXSize;
2166     const int nMainYSize = poGDS->m_poParentDS ?
2167                         poGDS->m_poParentDS->GetRasterYSize() : nRasterYSize;
2168     const int nULX = nBlockXOff * nBlockXSize;
2169     const int nULY = nBlockYOff * nBlockYSize;
2170     const int nLRX = std::min(nRasterXSize,
2171                             (nBlockXOff + nXBlocks) * nBlockXSize);
2172     const int nLRY = std::min(nRasterYSize,
2173                             (nBlockYOff + nYBlocks) * nBlockYSize);
2174 
2175     CPLJSONObject oUL;
2176     CPLJSONObject oLR;
2177     if( poGDS->m_bRequestInGeoreferencedCoordinates )
2178     {
2179         double dfULX, dfULY;
2180         GDALApplyGeoTransform(poGDS->m_adfGeoTransform.data(),
2181                               nULX, nULY, &dfULX, &dfULY);
2182         oUL.Add("x", dfULX);
2183         oUL.Add("y", dfULY);
2184 
2185         double dfLRX, dfLRY;
2186         GDALApplyGeoTransform(poGDS->m_adfGeoTransform.data(),
2187                               nLRX, nLRY, &dfLRX, &dfLRY);
2188         oLR.Add("x", dfLRX);
2189         oLR.Add("y", dfLRY);
2190     }
2191     else
2192     {
2193         oUL.Add("x", static_cast<int>(
2194             (static_cast<GIntBig>(nULX) * nMainXSize) / nRasterXSize) );
2195         oUL.Add("y", static_cast<int>(
2196             (static_cast<GIntBig>(nULY) * nMainYSize) / nRasterYSize) );
2197 
2198         oLR.Add("x", (nLRX == nRasterXSize) ? nMainXSize : static_cast<int>(
2199             (static_cast<GIntBig>(nLRX) * nMainXSize) / nRasterXSize));
2200         oLR.Add("y", (nLRY == nRasterYSize) ? nMainYSize : static_cast<int>(
2201             (static_cast<GIntBig>(nLRY) * nMainYSize) / nRasterYSize));
2202     }
2203     oBBox.Add("ul", oUL);
2204     oBBox.Add("lr", oLR);
2205     oDoc.GetRoot().Add("bbox", oBBox);
2206 
2207     CPLJSONObject oTargetModel;
2208 
2209     CPLJSONObject oStepTargetModel;
2210     if( poGDS->m_bRequestInGeoreferencedCoordinates )
2211     {
2212         oStepTargetModel.Add("x", poGDS->m_adfGeoTransform[1]);
2213         oStepTargetModel.Add("y", fabs(poGDS->m_adfGeoTransform[5]));
2214     }
2215     else
2216     {
2217         oStepTargetModel.Add("x", 0);
2218         oStepTargetModel.Add("y", 0);
2219     }
2220     oTargetModel.Add("step", oStepTargetModel);
2221 
2222     CPLJSONObject oSize;
2223     int nRequestWidth = nLRX - nULX;
2224     int nRequestHeight = nLRY - nULY;
2225     oSize.Add("columns", nRequestWidth);
2226     oSize.Add("lines", nRequestHeight);
2227     oTargetModel.Add("size", oSize);
2228 
2229     if( poGDS->m_eCurrentResampleAlg == GRIORA_NearestNeighbour )
2230     {
2231         oTargetModel.Add("sampling-algo", "NEAREST");
2232     }
2233     else if( poGDS->m_eCurrentResampleAlg == GRIORA_Bilinear )
2234     {
2235         oTargetModel.Add("sampling-algo", "BILINEAR");
2236     }
2237     else if( poGDS->m_eCurrentResampleAlg == GRIORA_Cubic )
2238     {
2239         oTargetModel.Add("sampling-algo", "BICUBIC");
2240     }
2241     else if( poGDS->m_eCurrentResampleAlg == GRIORA_Average )
2242     {
2243         oTargetModel.Add("sampling-algo", "AVERAGE");
2244     }
2245     else
2246     {
2247         // Defaults to BILINEAR for other GDAL methods not supported by
2248         // server
2249         oTargetModel.Add("sampling-algo", "BILINEAR");
2250     }
2251 
2252     oTargetModel.Add("strictOutputSize", true);
2253 
2254     if( !poGDS->m_bRequestInGeoreferencedCoordinates )
2255     {
2256         CPLJSONObject oSRS;
2257         oSRS.Add("type", "image");
2258         oTargetModel.Add("srs", oSRS);
2259     }
2260 
2261     oDoc.GetRoot().Add("target-model", oTargetModel);
2262 
2263 
2264     CPLJSONArray oBands;
2265     bool bOK = true;
2266     for( auto& iBand: anRequestedBands )
2267     {
2268         auto desc = (iBand == MAIN_MASK_BAND_NUMBER) ?
2269                                    poGDS->m_poMaskBand->GetDescription() :
2270                                    poGDS->GetRasterBand(iBand)->GetDescription();
2271         if( EQUAL(desc, "" ) )
2272             bOK = false;
2273         else
2274             oBands.Add( desc );
2275     }
2276     if( bOK )
2277     {
2278         oDoc.GetRoot().Add("bands", oBands);
2279     }
2280 
2281     papszOptions = CSLSetNameValue(papszOptions, "POSTFIELDS",
2282                         oDoc.GetRoot().Format(CPLJSONObject::PrettyFormat::Pretty).c_str());
2283 
2284     CPLString osURL( CPLGetConfigOption("GDAL_DAAS_GET_BUFFER_URL",
2285                                         poGDS->m_osGetBufferURL.c_str()) );
2286     CPLHTTPResult* psResult = DAAS_CPLHTTPFetch(osURL, papszOptions);
2287     CSLDestroy(papszOptions);
2288     if( psResult == nullptr )
2289         return CE_Failure;
2290 
2291     if( psResult->pszErrBuf != nullptr )
2292     {
2293         CPLError( CE_Failure, CPLE_AppDefined,
2294                   "Get request %s failed: %s",
2295                   osURL.c_str(),
2296                   psResult->pabyData ? CPLSPrintf("%s: %s",
2297                     psResult->pszErrBuf,
2298                     reinterpret_cast<const char*>(psResult->pabyData )) :
2299                   psResult->pszErrBuf );
2300         CPLHTTPDestroyResult(psResult);
2301         return CE_Failure;
2302     }
2303 
2304     if( psResult->nDataLen == 0 )
2305     {
2306         // Presumably HTTP 204 empty
2307         CPLHTTPDestroyResult(psResult);
2308 
2309         for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
2310         {
2311             for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
2312             {
2313                 for( auto& iBand: anRequestedBands )
2314                 {
2315                     GByte* pabyDstBuffer = nullptr;
2316                     GDALDAASRasterBand* poIterBand;
2317                     if( iBand == MAIN_MASK_BAND_NUMBER )
2318                     {
2319                         poIterBand = poGDS->m_poMaskBand;
2320                     }
2321                     else
2322                     {
2323                         poIterBand = reinterpret_cast<GDALDAASRasterBand*>(
2324                                                     poGDS->GetRasterBand(iBand));
2325                     }
2326 
2327                     GDALRasterBlock* poBlock = nullptr;
2328                     if(  pDstBuffer != nullptr )
2329                     {
2330                         pabyDstBuffer = static_cast<GByte*>(pDstBuffer);
2331                     }
2332                     else
2333                     {
2334                         // Check if the same block in other bands is already in
2335                         // the GDAL block cache
2336                         poBlock = poIterBand->TryGetLockedBlockRef(
2337                                 nBlockXOff + iXBlock, nBlockYOff + iYBlock);
2338                         if( poBlock != nullptr )
2339                         {
2340                             // Yes, no need to do further work
2341                             poBlock->DropLock();
2342                             continue;
2343                         }
2344                         // Instantiate the block
2345                         poBlock = poIterBand->GetLockedBlockRef(
2346                                     nBlockXOff + iXBlock,
2347                                     nBlockYOff + iYBlock, TRUE);
2348                         if (poBlock == nullptr)
2349                         {
2350                             continue;
2351                         }
2352                         pabyDstBuffer = static_cast<GByte*>(poBlock->GetDataRef());
2353                     }
2354 
2355                     const int nDTSize = GDALGetDataTypeSizeBytes(
2356                         poIterBand->GetRasterDataType());
2357                     double dfNoDataValue = poIterBand->GetNoDataValue(nullptr);
2358                     GDALCopyWords(&dfNoDataValue, GDT_Float64, 0,
2359                                   pabyDstBuffer,
2360                                   poIterBand->GetRasterDataType(),
2361                                   nDTSize,
2362                                   nBlockXSize * nBlockYSize);
2363                     if( poBlock )
2364                         poBlock->DropLock();
2365                 }
2366             }
2367         }
2368 
2369         return CE_None;
2370     }
2371 
2372 #ifdef DEBUG_VERBOSE
2373     CPLDebug("DAAS", "Response = '%s'",
2374              reinterpret_cast<const char*>(psResult->pabyData ));
2375 #endif
2376     if( !CPLHTTPParseMultipartMime(psResult) )
2377     {
2378         CPLError(CE_Failure, CPLE_AppDefined,
2379                  "Get request %s failed: "
2380                  "Invalid content returned by server",
2381                  osURL.c_str());
2382         CPLHTTPDestroyResult(psResult);
2383         return CE_Failure;
2384     }
2385     int iMetadataPart = -1;
2386     int iDataPart = -1;
2387     // Identify metadata and data parts
2388     for( int i = 0; i < psResult->nMimePartCount; i++ )
2389     {
2390         const char* pszContentType = CSLFetchNameValue(
2391             psResult->pasMimePart[i].papszHeaders, "Content-Type");
2392         const char* pszContentDisposition = CSLFetchNameValue(
2393             psResult->pasMimePart[i].papszHeaders, "Content-Disposition");
2394         if( pszContentType )
2395         {
2396             if( EQUAL(pszContentType, "application/json") )
2397             {
2398                 iMetadataPart = i;
2399             }
2400             else if( EQUAL(pszContentType, osDataContentType) )
2401             {
2402                 iDataPart = i;
2403             }
2404         }
2405         if( pszContentDisposition )
2406         {
2407             if( EQUAL(pszContentDisposition, "form-data; name=\"Data\";") )
2408             {
2409                 iDataPart = i;
2410             }
2411         }
2412     }
2413     if( iDataPart < 0 )
2414     {
2415         CPLError(CE_Failure, CPLE_AppDefined,
2416                  "Cannot find part with Content-Type: %s in GetBuffer response",
2417                  osDataContentType.c_str());
2418         CPLHTTPDestroyResult(psResult);
2419         return CE_Failure;
2420     }
2421     if( iMetadataPart < 0 )
2422     {
2423         CPLError(CE_Failure, CPLE_AppDefined,
2424                  "Cannot find part with Content-Type: %s in GetBuffer response",
2425                  "application/json");
2426         CPLHTTPDestroyResult(psResult);
2427         return CE_Failure;
2428     }
2429 
2430     CPLString osJson;
2431     osJson.assign(reinterpret_cast<const char*>(
2432                     psResult->pasMimePart[iMetadataPart].pabyData),
2433                   psResult->pasMimePart[iMetadataPart].nDataLen);
2434     CPLDebug("DAAS", "GetBuffer metadata response: %s", osJson.c_str());
2435     if( !oDoc.LoadMemory(osJson) )
2436     {
2437         CPLHTTPDestroyResult(psResult);
2438         return CE_Failure;
2439     }
2440     auto oDocRoot = oDoc.GetRoot();
2441     int nGotHeight = oDocRoot.GetInteger("properties/height");
2442     int nGotWidth = oDocRoot.GetInteger("properties/width");
2443     if( nGotHeight != nRequestHeight || nGotWidth != nRequestWidth )
2444     {
2445         CPLError(CE_Failure, CPLE_AppDefined,
2446                  "Got buffer of size %dx%d, whereas %dx%d was expected",
2447                  nGotWidth, nGotHeight, nRequestWidth, nRequestHeight);
2448         CPLHTTPDestroyResult(psResult);
2449         return CE_Failure;
2450     }
2451 
2452     // Get the actual data type of the buffer response
2453     GDALDataType eBufferDataType =
2454         anRequestedBands[0] == MAIN_MASK_BAND_NUMBER ? GDT_Byte : poGDS->m_aoBandDesc[anRequestedBands[0]-1].eDT;
2455     auto oBandArray = oDocRoot.GetArray("properties/bands");
2456     if( oBandArray.IsValid() && oBandArray.Size() >= 1 )
2457     {
2458         bool bIgnored;
2459         auto oBandProperties = oBandArray[0];
2460         auto osPixelType =
2461             GetString(oBandProperties, "pixelType", false, bIgnored);
2462         if( !osPixelType.empty() )
2463         {
2464             eBufferDataType = GetGDALDataTypeFromDAASPixelType(osPixelType);
2465             if( eBufferDataType == GDT_Unknown )
2466             {
2467                 CPLError(CE_Failure, CPLE_AppDefined,
2468                             "Invalid pixelType: %s", osPixelType.c_str());
2469                 CPLHTTPDestroyResult(psResult);
2470                 return CE_Failure;
2471             }
2472         }
2473     }
2474 
2475     const int nBufferDTSize = GDALGetDataTypeSizeBytes(eBufferDataType);
2476     GDALDataset* poTileDS;
2477     if( eRequestFormat == GDALDAASDataset::Format::RAW )
2478     {
2479         int nExpectedBytes = nGotHeight * nGotWidth * nBufferDTSize *
2480             static_cast<int>(anRequestedBands.size());
2481         if( psResult->pasMimePart[iDataPart].nDataLen != nExpectedBytes )
2482         {
2483             CPLError(CE_Failure, CPLE_AppDefined,
2484                     "Got buffer of %d bytes, whereas %d were expected",
2485                     psResult->pasMimePart[iDataPart].nDataLen, nExpectedBytes);
2486             CPLHTTPDestroyResult(psResult);
2487             return CE_Failure;
2488         }
2489 
2490         GByte* pabySrcData = psResult->pasMimePart[iDataPart].pabyData;
2491 #ifdef CPL_MSB
2492         GDALSwapWords( pabySrcData,
2493                     nBufferDTSize,
2494                     nGotHeight * nGotWidth * static_cast<int>(anRequestedBands.size()),
2495                     nBufferDTSize );
2496 #endif
2497 
2498         poTileDS = MEMDataset::Create(
2499             "", nRequestWidth, nRequestHeight, 0, eBufferDataType, nullptr);
2500         for( int i = 0; i < static_cast<int>(anRequestedBands.size()); i++ )
2501         {
2502             char szBuffer0[128] = {};
2503             char szBuffer[64] = {};
2504             int nRet = CPLPrintPointer(
2505                 szBuffer,
2506                 pabySrcData + i * nGotHeight * nGotWidth * nBufferDTSize,
2507                 sizeof(szBuffer));
2508             szBuffer[nRet] = 0;
2509             snprintf(szBuffer0, sizeof(szBuffer0), "DATAPOINTER=%s", szBuffer);
2510             char* apszOptions[2] = { szBuffer0, nullptr };
2511             poTileDS->AddBand(eBufferDataType, apszOptions);
2512         }
2513     }
2514     else
2515     {
2516         CPLString osTmpMemFile = CPLSPrintf("/vsimem/daas_%p", this);
2517         VSIFCloseL( VSIFileFromMemBuffer( osTmpMemFile,
2518                                 psResult->pasMimePart[iDataPart].pabyData,
2519                                 psResult->pasMimePart[iDataPart].nDataLen,
2520                                 false ) );
2521         poTileDS = reinterpret_cast<GDALDataset*>(
2522                     GDALOpenEx(osTmpMemFile, GDAL_OF_RASTER | GDAL_OF_INTERNAL,
2523                            nullptr, nullptr, nullptr));
2524         if( !poTileDS )
2525         {
2526             CPLError(CE_Failure, CPLE_AppDefined,
2527                      "Cannot decode image");
2528             VSIUnlink(osTmpMemFile);
2529             CPLHTTPDestroyResult(psResult);
2530             return CE_Failure;
2531         }
2532     }
2533 
2534     CPLErr eErr = CE_None;
2535     std::shared_ptr<GDALDataset> ds =
2536                 std::shared_ptr<GDALDataset>(poTileDS);
2537     poTileDS->MarkSuppressOnClose();
2538 
2539     bool bExpectedImageCharacteristics =
2540          (poTileDS->GetRasterXSize() == nRequestWidth &&
2541           poTileDS->GetRasterYSize() == nRequestHeight);
2542     if( bExpectedImageCharacteristics )
2543     {
2544         if( poTileDS->GetRasterCount() == static_cast<int>(anRequestedBands.size()) )
2545         {
2546             // ok
2547         }
2548         else if( eRequestFormat == GDALDAASDataset::Format::PNG &&
2549                  anRequestedBands.size() == 1 &&
2550                  poTileDS->GetRasterCount() == 4 )
2551         {
2552             // ok
2553         }
2554         else
2555         {
2556             bExpectedImageCharacteristics = false;
2557         }
2558     }
2559 
2560     if( !bExpectedImageCharacteristics )
2561     {
2562         CPLError(CE_Failure, CPLE_AppDefined,
2563             "Got tile of size %dx%dx%d, whereas %dx%dx%d was expected",
2564             poTileDS->GetRasterXSize(),
2565             poTileDS->GetRasterYSize(),
2566             poTileDS->GetRasterCount(),
2567             nRequestWidth, nRequestHeight, static_cast<int>(anRequestedBands.size()));
2568         CPLHTTPDestroyResult(psResult);
2569         return CE_Failure;
2570     }
2571 
2572     for( int iYBlock = 0; eErr == CE_None && iYBlock < nYBlocks; iYBlock++ )
2573     {
2574         int nBlockActualYSize = std::min(nBlockYSize,
2575                     nRasterYSize - (iYBlock + nBlockYOff) * nBlockYSize);
2576         for( int iXBlock = 0; eErr == CE_None && iXBlock < nXBlocks; iXBlock++ )
2577         {
2578             int nBlockActualXSize = std::min(nBlockXSize,
2579                         nRasterXSize - (iXBlock + nBlockXOff) * nBlockXSize);
2580 
2581             for( int i = 0; i < static_cast<int>(anRequestedBands.size()); i++ )
2582             {
2583                 const int iBand = anRequestedBands[i];
2584                 GByte* pabyDstBuffer = nullptr;
2585                 GDALDAASRasterBand* poIterBand;
2586                 if( iBand == MAIN_MASK_BAND_NUMBER )
2587                 {
2588                     poIterBand = poGDS->m_poMaskBand;
2589                 }
2590                 else
2591                 {
2592                     poIterBand = reinterpret_cast<GDALDAASRasterBand*>(
2593                                                 poGDS->GetRasterBand(iBand));
2594                 }
2595 
2596                 GDALRasterBlock* poBlock = nullptr;
2597                 if( pDstBuffer != nullptr )
2598                     pabyDstBuffer = static_cast<GByte*>(pDstBuffer);
2599                 else
2600                 {
2601                     // Check if the same block in other bands is already in
2602                     // the GDAL block cache
2603                     poBlock = poIterBand->TryGetLockedBlockRef(
2604                             nBlockXOff + iXBlock, nBlockYOff + iYBlock);
2605                     if( poBlock != nullptr )
2606                     {
2607                         // Yes, no need to do further work
2608                         poBlock->DropLock();
2609                         continue;
2610                     }
2611                     // Instantiate the block
2612                     poBlock = poIterBand->GetLockedBlockRef(
2613                                 nBlockXOff + iXBlock,
2614                                 nBlockYOff + iYBlock, TRUE);
2615                     if (poBlock == nullptr)
2616                     {
2617                         continue;
2618                     }
2619                     pabyDstBuffer = static_cast<GByte*>(poBlock->GetDataRef());
2620                 }
2621 
2622                 GDALRasterBand* poTileBand = poTileDS->GetRasterBand(i + 1);
2623                 const auto eIterBandDT = poIterBand->GetRasterDataType();
2624                 const int nDTSize = GDALGetDataTypeSizeBytes(eIterBandDT);
2625                 eErr = poTileBand->RasterIO(GF_Read,
2626                     iXBlock * nBlockXSize,
2627                     iYBlock * nBlockYSize,
2628                     nBlockActualXSize, nBlockActualYSize,
2629                     pabyDstBuffer,
2630                     nBlockActualXSize, nBlockActualYSize,
2631                     eIterBandDT,
2632                     nDTSize, nDTSize * nBlockXSize, nullptr);
2633 
2634                 if( poBlock )
2635                     poBlock->DropLock();
2636                 if( eErr != CE_None )
2637                     break;
2638             }
2639         }
2640     }
2641 
2642     CPLHTTPDestroyResult(psResult);
2643     return eErr;
2644 }
2645 
2646 /************************************************************************/
2647 /*                       GDALRegister_DAAS()                            */
2648 /************************************************************************/
2649 
GDALRegister_DAAS()2650 void GDALRegister_DAAS()
2651 
2652 {
2653     if( GDALGetDriverByName( "DAAS" ) != nullptr )
2654         return;
2655 
2656     GDALDriver *poDriver = new GDALDriver();
2657 
2658     poDriver->SetDescription( "DAAS" );
2659     poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
2660     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
2661                                "Airbus DS Intelligence "
2662                                "Data As A Service driver" );
2663     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2664                                "drivers/raster/daas.html" );
2665 
2666     poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
2667 "<OpenOptionList>"
2668 "  <Option name='GET_METADATA_URL' type='string' "
2669         "description='URL to GetImageMetadata' "
2670         "required='true'/>"
2671 "  <Option name='API_KEY' alt_config_option='GDAL_DAAS_API_KEY' type='string' "
2672         "description='API key'/>"
2673 "  <Option name='CLIENT_ID' alt_config_option='GDAL_DAAS_CLIENT_ID' "
2674         "type='string' description='Client id'/>"
2675 "  <Option name='ACCESS_TOKEN' alt_config_option='GDAL_DAAS_ACCESS_TOKEN' "
2676         "type='string' description='Authorization access token'/>"
2677 "  <Option name='X_FORWARDED_USER' "
2678         "alt_config_option='GDAL_DAAS_X_FORWARDED_USER' type='string' "
2679         "description='User from which the request originates from'/>"
2680 "  <Option name='BLOCK_SIZE' type='integer' "
2681                                 "description='Size of a block' default='512'/>"
2682 "  <Option name='PIXEL_ENCODING' type='string-select' "
2683                         "description='Format in which pixels are queried'>"
2684 "       <Value>AUTO</Value>"
2685 "       <Value>RAW</Value>"
2686 "       <Value>PNG</Value>"
2687 "       <Value>JPEG</Value>"
2688 "       <Value>JPEG2000</Value>"
2689 "   </Option>"
2690 "  <Option name='TARGET_SRS' type='string' description="
2691                                 "'SRS name for server-side reprojection.'/>"
2692 "  <Option name='MASKS' type='boolean' "
2693                     "description='Whether to expose mask bands' default='YES'/>"
2694 "</OpenOptionList>" );
2695 
2696     poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "DAAS:" );
2697 
2698     poDriver->pfnIdentify = GDALDAASDataset::Identify;
2699     poDriver->pfnOpen = GDALDAASDataset::OpenStatic;
2700 
2701     GetGDALDriverManager()->RegisterDriver( poDriver );
2702 }
2703