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