• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.27
/frmts/eeda/eedadataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  Earth Engine Data API driver
4
 * Purpose:  Earth Engine Data API driver
5
 * Author:   Even Rouault, even dot rouault at spatialys.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2017-2018, Planet Labs
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "gdal_priv.h"
14
#include "ogrsf_frmts.h"
15
#include "cpl_http.h"
16
#include "cpl_conv.h"
17
#include "ogrlibjsonutils.h"
18
#include "ogr_swq.h"
19
#include "eeda.h"
20

21
#include <algorithm>
22
#include <cinttypes>
23
#include <vector>
24
#include <map>
25
#include <set>
26
#include <limits>
27

28
extern "C" void GDALRegister_EEDA();
29

30
/************************************************************************/
31
/*                     CPLEscapeURLQueryParameter()                     */
32
/************************************************************************/
33

34
static CPLString CPLEscapeURLQueryParameter(const char *pszInput)
9✔
35
{
36
    int nLength = static_cast<int>(strlen(pszInput));
9✔
37

38
    const size_t nSizeAlloc = nLength * 4 + 1;
9✔
39
    char *pszOutput = static_cast<char *>(CPLMalloc(nSizeAlloc));
9✔
40
    int iOut = 0;
9✔
41

42
    for (int iIn = 0; iIn < nLength; ++iIn)
506✔
43
    {
44
        if ((pszInput[iIn] >= 'a' && pszInput[iIn] <= 'z') ||
497✔
45
            (pszInput[iIn] >= 'A' && pszInput[iIn] <= 'Z') ||
357✔
46
            (pszInput[iIn] >= '0' && pszInput[iIn] <= '9'))
317✔
47
        {
48
            pszOutput[iOut++] = pszInput[iIn];
310✔
49
        }
50
        else
51
        {
52
            snprintf(pszOutput + iOut, nSizeAlloc - iOut, "%%%02X",
187✔
53
                     static_cast<unsigned char>(pszInput[iIn]));
187✔
54
            iOut += 3;
187✔
55
        }
56
    }
57
    pszOutput[iOut] = '\0';
9✔
58

59
    CPLString osRet(pszOutput);
9✔
60
    CPLFree(pszOutput);
9✔
61
    return osRet;
9✔
62
}
63

64
/************************************************************************/
65
/*                          GDALEEDADataset                             */
66
/************************************************************************/
67

68
class GDALEEDALayer;
69

70
class GDALEEDADataset final : public GDALEEDABaseDataset
71
{
72
    CPL_DISALLOW_COPY_ASSIGN(GDALEEDADataset)
73

74
    GDALEEDALayer *m_poLayer;
75

76
  public:
77
    GDALEEDADataset();
78
    virtual ~GDALEEDADataset();
79

80
    virtual int GetLayerCount() CPL_OVERRIDE
×
81
    {
82
        return m_poLayer ? 1 : 0;
×
83
    }
84

85
    virtual OGRLayer *GetLayer(int idx) CPL_OVERRIDE;
86

87
    bool Open(GDALOpenInfo *poOpenInfo);
88
    json_object *RunRequest(const CPLString &osURL);
89

90
    const CPLString &GetBaseURL() const
7✔
91
    {
92
        return m_osBaseURL;
7✔
93
    }
94
};
95

96
/************************************************************************/
97
/*                          GDALEEDALayer                               */
98
/************************************************************************/
99

100
class GDALEEDALayer final : public OGRLayer
101
{
102
    CPL_DISALLOW_COPY_ASSIGN(GDALEEDALayer)
103

104
    GDALEEDADataset *m_poDS;
105
    CPLString m_osCollection{};
106
    CPLString m_osCollectionName{};
107
    OGRFeatureDefn *m_poFeatureDefn;
108
    json_object *m_poCurPageObj;
109
    json_object *m_poCurPageAssets;
110
    int m_nIndexInPage;
111
    GIntBig m_nFID;
112
    CPLString m_osAttributeFilter{};
113
    CPLString m_osStartTime{};
114
    CPLString m_osEndTime{};
115
    bool m_bFilterMustBeClientSideEvaluated;
116
    std::set<int> m_oSetQueryableFields{};
117
    std::map<CPLString, CPLString> m_oMapCodeToWKT{};
118

119
    OGRFeature *GetNextRawFeature();
120
    bool IsSimpleComparison(const swq_expr_node *poNode);
121
    CPLString BuildFilter(swq_expr_node *poNode, bool bIsAndTopLevel);
122

123
  public:
124
    GDALEEDALayer(GDALEEDADataset *poDS, const CPLString &osCollection,
125
                  const CPLString &osCollectionName, json_object *poAsset,
126
                  json_object *poLayerConf);
127
    virtual ~GDALEEDALayer();
128

129
    virtual void ResetReading() CPL_OVERRIDE;
130
    virtual OGRFeature *GetNextFeature() CPL_OVERRIDE;
131
    virtual int TestCapability(const char *) CPL_OVERRIDE;
132

133
    virtual OGRFeatureDefn *GetLayerDefn() CPL_OVERRIDE
8✔
134
    {
135
        return m_poFeatureDefn;
8✔
136
    }
137

138
    virtual GIntBig GetFeatureCount(int) CPL_OVERRIDE
1✔
139
    {
140
        return -1;
1✔
141
    }
142

143
    virtual OGRErr ISetSpatialFilter(int iGeomField,
144
                                     const OGRGeometry *poGeom) override;
145

146
    virtual OGRErr SetAttributeFilter(const char *) CPL_OVERRIDE;
147

148
    virtual OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
149
                              bool bForce) override;
150
};
151

152
/************************************************************************/
153
/*                            GDALEEDALayer()                           */
154
/************************************************************************/
155

156
GDALEEDALayer::GDALEEDALayer(GDALEEDADataset *poDS,
7✔
157
                             const CPLString &osCollection,
158
                             const CPLString &osCollectionName,
159
                             json_object *poAsset, json_object *poLayerConf)
7✔
160
    : m_poDS(poDS), m_osCollection(osCollection),
161
      m_osCollectionName(osCollectionName), m_poFeatureDefn(nullptr),
162
      m_poCurPageObj(nullptr), m_poCurPageAssets(nullptr), m_nIndexInPage(0),
163
      m_nFID(1), m_bFilterMustBeClientSideEvaluated(true)
7✔
164
{
165
    CPLString osLaundered(osCollection);
7✔
166
    for (size_t i = 0; i < osLaundered.size(); i++)
126✔
167
    {
168
        if (!isalnum(static_cast<unsigned char>(osLaundered[i])))
119✔
169
        {
170
            osLaundered[i] = '_';
13✔
171
        }
172
    }
173
    SetDescription(osLaundered);
7✔
174
    m_poFeatureDefn = new OGRFeatureDefn(osLaundered);
7✔
175
    m_poFeatureDefn->Reference();
7✔
176
    m_poFeatureDefn->SetGeomType(wkbMultiPolygon);
7✔
177
    OGRSpatialReference *poSRS = new OGRSpatialReference();
7✔
178
    poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
7✔
179
    m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
7✔
180
    poSRS->Release();
7✔
181

182
    {
183
        OGRFieldDefn oFieldDefn("name", OFTString);
14✔
184
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
185
    }
186
    {
187
        OGRFieldDefn oFieldDefn("id", OFTString);
14✔
188
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
189
    }
190
    {
191
        OGRFieldDefn oFieldDefn("gdal_dataset", OFTString);
14✔
192
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
193
    }
194
    {
195
        OGRFieldDefn oFieldDefn("updateTime", OFTDateTime);
14✔
196
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
197
    }
198
    {
199
        OGRFieldDefn oFieldDefn("startTime", OFTDateTime);
14✔
200
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
201
    }
202
    {
203
        OGRFieldDefn oFieldDefn("endTime", OFTDateTime);
14✔
204
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
205
    }
206
    {
207
        OGRFieldDefn oFieldDefn("sizeBytes", OFTInteger64);
14✔
208
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
209
    }
210
    {
211
        OGRFieldDefn oFieldDefn("band_count", OFTInteger);
14✔
212
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
213
    }
214
    {
215
        OGRFieldDefn oFieldDefn("band_max_width", OFTInteger);
14✔
216
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
217
    }
218
    {
219
        OGRFieldDefn oFieldDefn("band_max_height", OFTInteger);
14✔
220
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
221
    }
222
    {
223
        OGRFieldDefn oFieldDefn("band_min_pixel_size", OFTReal);
14✔
224
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
225
    }
226
    {
227
        OGRFieldDefn oFieldDefn("band_upper_left_x", OFTReal);
14✔
228
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
229
    }
230
    {
231
        OGRFieldDefn oFieldDefn("band_upper_left_y", OFTReal);
14✔
232
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
233
    }
234
    {
235
        OGRFieldDefn oFieldDefn("band_crs", OFTString);
14✔
236
        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
7✔
237
    }
238

239
    if (poLayerConf)
7✔
240
    {
241
        json_object *poFields =
242
            CPL_json_object_object_get(poLayerConf, "fields");
1✔
243
        if (poFields == nullptr ||
2✔
244
            json_object_get_type(poFields) != json_type_array)
1✔
245
        {
246
            CPLError(CE_Failure, CPLE_AppDefined,
×
247
                     "Cannot find %s.fields object in eedaconf.json",
248
                     GetDescription());
249
            return;
×
250
        }
251

252
        const auto nFields = json_object_array_length(poFields);
1✔
253
        for (auto i = decltype(nFields){0}; i < nFields; i++)
5✔
254
        {
255
            json_object *poField = json_object_array_get_idx(poFields, i);
4✔
256
            if (poField && json_object_get_type(poField) == json_type_object)
4✔
257
            {
258
                json_object *poName =
259
                    CPL_json_object_object_get(poField, "name");
4✔
260
                json_object *poType =
261
                    CPL_json_object_object_get(poField, "type");
4✔
262
                if (poName &&
8✔
263
                    json_object_get_type(poName) == json_type_string &&
4✔
264
                    poType && json_object_get_type(poType) == json_type_string)
8✔
265
                {
266
                    const char *pszName = json_object_get_string(poName);
4✔
267
                    const char *pszType = json_object_get_string(poType);
4✔
268
                    OGRFieldType eType(OFTString);
4✔
269
                    if (EQUAL(pszType, "datetime"))
4✔
270
                        eType = OFTDateTime;
×
271
                    else if (EQUAL(pszType, "double"))
4✔
272
                        eType = OFTReal;
1✔
273
                    else if (EQUAL(pszType, "int"))
3✔
274
                        eType = OFTInteger;
1✔
275
                    else if (EQUAL(pszType, "int64"))
2✔
276
                        eType = OFTInteger64;
2✔
277
                    else if (EQUAL(pszType, "string"))
×
278
                        eType = OFTString;
×
279
                    else
280
                    {
281
                        CPLError(CE_Warning, CPLE_AppDefined,
×
282
                                 "Unrecognized field type %s for field %s",
283
                                 pszType, pszName);
284
                    }
285
                    OGRFieldDefn oFieldDefn(pszName, eType);
4✔
286
                    m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
4✔
287
                    m_oSetQueryableFields.insert(
288
                        m_poFeatureDefn->GetFieldCount() - 1);
4✔
289
                }
290
            }
291
        }
292

293
        json_object *poAddOtherProp = CPL_json_object_object_get(
1✔
294
            poLayerConf, "add_other_properties_field");
295
        if (json_object_get_boolean(poAddOtherProp))
1✔
296
        {
297
            OGRFieldDefn oFieldDefn("other_properties", OFTString);
2✔
298
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
1✔
299
        }
300
    }
301
    else
302
    {
303
        json_object *poProperties =
304
            CPL_json_object_object_get(poAsset, "properties");
6✔
305
        if (poProperties != nullptr &&
7✔
306
            json_object_get_type(poProperties) == json_type_object)
1✔
307
        {
308
            json_object_iter it;
309
            it.key = nullptr;
1✔
310
            it.val = nullptr;
1✔
311
            it.entry = nullptr;
1✔
312
            json_object_object_foreachC(poProperties, it)
5✔
313
            {
314
                OGRFieldType eType(OFTString);
4✔
315
                if (it.val)
4✔
316
                {
317
                    if (json_object_get_type(it.val) == json_type_int)
4✔
318
                    {
319
                        if (strstr(it.key, "PERCENTAGE"))
2✔
320
                            eType = OFTReal;
×
321
                        else if (CPLAtoGIntBig(json_object_get_string(it.val)) >
2✔
322
                                 INT_MAX)
323
                            eType = OFTInteger64;
1✔
324
                        else
325
                            eType = OFTInteger;
1✔
326
                    }
327
                    else if (json_object_get_type(it.val) == json_type_double)
2✔
328
                    {
329
                        eType = OFTReal;
1✔
330
                    }
331
                }
332
                OGRFieldDefn oFieldDefn(it.key, eType);
4✔
333
                m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
4✔
334
                m_oSetQueryableFields.insert(m_poFeatureDefn->GetFieldCount() -
4✔
335
                                             1);
4✔
336
            }
337
        }
338
        {
339
            OGRFieldDefn oFieldDefn("other_properties", OFTString);
12✔
340
            m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
6✔
341
        }
342
    }
343
}
344

345
/************************************************************************/
346
/*                           ~GDALEEDALayer()                           */
347
/************************************************************************/
348

349
GDALEEDALayer::~GDALEEDALayer()
14✔
350
{
351
    m_poFeatureDefn->Release();
7✔
352
    if (m_poCurPageObj)
7✔
353
        json_object_put(m_poCurPageObj);
1✔
354
}
14✔
355

356
/************************************************************************/
357
/*                            ResetReading()                            */
358
/************************************************************************/
359

360
void GDALEEDALayer::ResetReading()
11✔
361
{
362
    if (m_poCurPageObj)
11✔
363
        json_object_put(m_poCurPageObj);
5✔
364
    m_poCurPageObj = nullptr;
11✔
365
    m_poCurPageAssets = nullptr;
11✔
366
    m_nIndexInPage = 0;
11✔
367
    m_nFID = 1;
11✔
368
}
11✔
369

370
/************************************************************************/
371
/*                        GetNextRawFeature()                           */
372
/************************************************************************/
373

374
OGRFeature *GDALEEDALayer::GetNextRawFeature()
9✔
375
{
376
    CPLString osNextPageToken;
18✔
377
    if (m_poCurPageAssets != nullptr &&
12✔
378
        m_nIndexInPage >=
6✔
379
            static_cast<int>(json_object_array_length(m_poCurPageAssets)))
3✔
380
    {
381
        json_object *poToken =
382
            CPL_json_object_object_get(m_poCurPageObj, "nextPageToken");
2✔
383
        const char *pszToken = json_object_get_string(poToken);
2✔
384
        if (pszToken == nullptr)
2✔
385
            return nullptr;
1✔
386
        osNextPageToken = pszToken;
1✔
387
        json_object_put(m_poCurPageObj);
1✔
388
        m_poCurPageObj = nullptr;
1✔
389
        m_poCurPageAssets = nullptr;
1✔
390
        m_nIndexInPage = 0;
1✔
391
    }
392

393
    if (m_poCurPageObj == nullptr)
8✔
394
    {
395
        CPLString osURL(m_poDS->GetBaseURL() + m_osCollectionName +
14✔
396
                        ":listImages");
7✔
397
        CPLString query = "";
7✔
398
        if (!osNextPageToken.empty())
7✔
399
        {
400
            query +=
401
                "&pageToken=" + CPLEscapeURLQueryParameter(osNextPageToken);
1✔
402
        }
403
        const char *pszPageSize = CPLGetConfigOption("EEDA_PAGE_SIZE", nullptr);
7✔
404
        if (pszPageSize)
7✔
405
        {
406
            query += "&pageSize=";
×
407
            query += pszPageSize;
×
408
        }
409
        if (m_poFilterGeom != nullptr)
7✔
410
        {
411
            char *pszGeoJSON =
412
                OGR_G_ExportToJson(OGRGeometry::ToHandle(m_poFilterGeom));
1✔
413
            query += "&region=";
1✔
414
            query += CPLEscapeURLQueryParameter(pszGeoJSON);
1✔
415
            CPLFree(pszGeoJSON);
1✔
416
        }
417
        if (!m_osAttributeFilter.empty())
7✔
418
        {
419
            query += "&filter=";
2✔
420
            query += CPLEscapeURLQueryParameter(m_osAttributeFilter);
2✔
421
        }
422
        if (!m_osStartTime.empty())
7✔
423
        {
424
            query += "&startTime=";
3✔
425
            query += CPLEscapeURLQueryParameter(m_osStartTime);
3✔
426
        }
427
        if (!m_osEndTime.empty())
7✔
428
        {
429
            query += "&endTime=";
2✔
430
            query += CPLEscapeURLQueryParameter(m_osEndTime);
2✔
431
        }
432
        if (query.size() > 0)
7✔
433
        {
434
            osURL = osURL + "?" + query.substr(1);
5✔
435
        }
436
        m_poCurPageObj = m_poDS->RunRequest(osURL);
7✔
437
        if (m_poCurPageObj == nullptr)
7✔
438
            return nullptr;
×
439

440
        m_poCurPageAssets =
7✔
441
            CPL_json_object_object_get(m_poCurPageObj, "images");
7✔
442
    }
443

444
    if (m_poCurPageAssets == nullptr ||
16✔
445
        json_object_get_type(m_poCurPageAssets) != json_type_array)
8✔
446
    {
447
        json_object_put(m_poCurPageObj);
×
448
        m_poCurPageObj = nullptr;
×
449
        return nullptr;
×
450
    }
451
    json_object *poAsset =
452
        json_object_array_get_idx(m_poCurPageAssets, m_nIndexInPage);
8✔
453
    if (poAsset == nullptr || json_object_get_type(poAsset) != json_type_object)
8✔
454
    {
455
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid asset");
×
456
        return nullptr;
×
457
    }
458

459
    OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn);
8✔
460
    poFeature->SetFID(m_nFID);
8✔
461

462
    json_object *poJSonGeom = CPL_json_object_object_get(poAsset, "geometry");
8✔
463
    if (poJSonGeom != nullptr &&
11✔
464
        json_object_get_type(poJSonGeom) == json_type_object)
3✔
465
    {
466
        const char *pszGeoJSON = json_object_get_string(poJSonGeom);
3✔
467
        if (strstr(pszGeoJSON, "Infinity") == nullptr)
3✔
468
        {
469
            OGRGeometry *poGeom = OGRGeometry::FromHandle(
3✔
470
                OGR_G_CreateGeometryFromJson(pszGeoJSON));
471
            if (poGeom != nullptr)
3✔
472
            {
473
                if (poGeom->getGeometryType() == wkbPolygon)
3✔
474
                {
475
                    OGRMultiPolygon *poMP = new OGRMultiPolygon();
3✔
476
                    poMP->addGeometryDirectly(poGeom);
3✔
477
                    poGeom = poMP;
3✔
478
                }
479
                poGeom->assignSpatialReference(
3✔
480
                    m_poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef());
3✔
481
                poFeature->SetGeometryDirectly(poGeom);
3✔
482
            }
483
        }
484
    }
485

486
    const char *pszName =
487
        json_object_get_string(CPL_json_object_object_get(poAsset, "name"));
8✔
488
    if (pszName)
8✔
489
    {
490
        poFeature->SetField("name", pszName);
8✔
491
        poFeature->SetField("gdal_dataset",
8✔
492
                            ("EEDAI:" + CPLString(pszName)).c_str());
16✔
493
    }
494

495
    const char *pszId =
496
        json_object_get_string(CPL_json_object_object_get(poAsset, "id"));
8✔
497
    if (pszId)
8✔
498
    {
499
        poFeature->SetField("id", pszId);
2✔
500
    }
501

502
    const char *const apszBaseProps[] = {"updateTime", "startTime", "endTime",
8✔
503
                                         "sizeBytes"};
504
    for (size_t i = 0; i < CPL_ARRAYSIZE(apszBaseProps); i++)
40✔
505
    {
506
        const char *pszVal = json_object_get_string(
32✔
507
            CPL_json_object_object_get(poAsset, apszBaseProps[i]));
32✔
508
        if (pszVal)
32✔
509
        {
510
            poFeature->SetField(apszBaseProps[i], pszVal);
15✔
511
        }
512
    }
513

514
    json_object *poBands = CPL_json_object_object_get(poAsset, "bands");
8✔
515
    if (poBands != nullptr && json_object_get_type(poBands) == json_type_array)
8✔
516
    {
517
        std::vector<EEDAIBandDesc> aoBands =
518
            BuildBandDescArray(poBands, m_oMapCodeToWKT);
4✔
519
        poFeature->SetField("band_count", static_cast<int>(aoBands.size()));
2✔
520
        if (!aoBands.empty())
2✔
521
        {
522
            int nWidth = 0, nHeight = 0;
2✔
523
            double dfMinPixelSize = std::numeric_limits<double>::max();
2✔
524
            CPLString osSRS(aoBands[0].osWKT);
4✔
525
            double dfULX = aoBands[0].gt[0];
2✔
526
            double dfULY = aoBands[0].gt[3];
2✔
527
            bool bULValid = true;
2✔
528
            for (size_t i = 0; i < aoBands.size(); i++)
4✔
529
            {
530
                nWidth = std::max(nWidth, aoBands[i].nWidth);
2✔
531
                nHeight = std::max(nHeight, aoBands[i].nHeight);
2✔
532
                dfMinPixelSize =
2✔
533
                    std::min(dfMinPixelSize, std::min(aoBands[i].gt[1],
2✔
534
                                                      fabs(aoBands[i].gt[5])));
4✔
535
                if (osSRS != aoBands[i].osWKT)
2✔
536
                {
537
                    osSRS.clear();
×
538
                }
539
                if (dfULX != aoBands[i].gt[0] || dfULY != aoBands[i].gt[3])
2✔
540
                {
541
                    bULValid = false;
×
542
                }
543
            }
544
            poFeature->SetField("band_max_width", nWidth);
2✔
545
            poFeature->SetField("band_max_height", nHeight);
2✔
546
            poFeature->SetField("band_min_pixel_size", dfMinPixelSize);
2✔
547
            if (bULValid)
2✔
548
            {
549
                poFeature->SetField("band_upper_left_x", dfULX);
2✔
550
                poFeature->SetField("band_upper_left_y", dfULY);
2✔
551
            }
552
            if (!osSRS.empty())
2✔
553
            {
554
                OGRSpatialReference oSRS;
4✔
555
                oSRS.SetFromUserInput(
2✔
556
                    osSRS,
557
                    OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
558
                const char *pszAuthName = oSRS.GetAuthorityName(nullptr);
2✔
559
                const char *pszAuthCode = oSRS.GetAuthorityCode(nullptr);
2✔
560
                if (pszAuthName && pszAuthCode)
2✔
561
                {
562
                    poFeature->SetField(
2✔
563
                        "band_crs",
564
                        CPLSPrintf("%s:%s", pszAuthName, pszAuthCode));
565
                }
566
                else
567
                {
568
                    poFeature->SetField("band_crs", osSRS.c_str());
×
569
                }
570
            }
571
        }
572
    }
573

574
    json_object *poProperties =
575
        CPL_json_object_object_get(poAsset, "properties");
8✔
576
    if (poProperties != nullptr &&
11✔
577
        json_object_get_type(poProperties) == json_type_object)
3✔
578
    {
579
        json_object *poOtherProperties = nullptr;
3✔
580

581
        json_object_iter it;
582
        it.key = nullptr;
3✔
583
        it.val = nullptr;
3✔
584
        it.entry = nullptr;
3✔
585
        json_object_object_foreachC(poProperties, it)
18✔
586
        {
587
            if (it.val)
15✔
588
            {
589
                int nIdx = m_poFeatureDefn->GetFieldIndex(it.key);
15✔
590
                if (nIdx >= 0)
15✔
591
                {
592
                    poFeature->SetField(nIdx, json_object_get_string(it.val));
12✔
593
                }
594
                else
595
                {
596
                    if (poOtherProperties == nullptr)
3✔
597
                        poOtherProperties = json_object_new_object();
3✔
598
                    json_object_object_add(poOtherProperties, it.key, it.val);
3✔
599
                    json_object_get(it.val);
3✔
600
                }
601
            }
602
        }
603

604
        if (poOtherProperties)
3✔
605
        {
606
            int nIdxOtherProperties =
607
                m_poFeatureDefn->GetFieldIndex("other_properties");
3✔
608
            if (nIdxOtherProperties >= 0)
3✔
609
            {
610
                poFeature->SetField(nIdxOtherProperties,
3✔
611
                                    json_object_get_string(poOtherProperties));
612
            }
613
            json_object_put(poOtherProperties);
3✔
614
        }
615
    }
616

617
    m_nFID++;
8✔
618
    m_nIndexInPage++;
8✔
619

620
    return poFeature;
8✔
621
}
622

623
/************************************************************************/
624
/*                           GetNextFeature()                           */
625
/************************************************************************/
626

627
OGRFeature *GDALEEDALayer::GetNextFeature()
9✔
628
{
629
    while (true)
630
    {
631
        OGRFeature *poFeature = GetNextRawFeature();
9✔
632
        if (poFeature == nullptr)
9✔
633
            return nullptr;
1✔
634

635
        if (m_poAttrQuery == nullptr || !m_bFilterMustBeClientSideEvaluated ||
8✔
636
            m_poAttrQuery->Evaluate(poFeature))
×
637
        {
638
            return poFeature;
8✔
639
        }
640
        else
641
        {
642
            delete poFeature;
×
643
        }
644
    }
×
645
}
646

647
/************************************************************************/
648
/*                      GDALEEDALayerParseDateTime()                    */
649
/************************************************************************/
650

651
static int GDALEEDALayerParseDateTime(const char *pszValue, int operation,
5✔
652
                                      int &nYear, int &nMonth, int &nDay,
653
                                      int &nHour, int &nMinute, int &nSecond)
654
{
655
    nHour = (operation == SWQ_GE) ? 0 : 23;
5✔
656
    nMinute = (operation == SWQ_GE) ? 0 : 59;
5✔
657
    nSecond = (operation == SWQ_GE) ? 0 : 59;
5✔
658
    int nRet = sscanf(pszValue, "%04d/%02d/%02d %02d:%02d:%02d", &nYear,
5✔
659
                      &nMonth, &nDay, &nHour, &nMinute, &nSecond);
660
    if (nRet >= 3)
5✔
661
    {
662
        return nRet;
×
663
    }
664
    nRet = sscanf(pszValue, "%04d-%02d-%02dT%02d:%02d:%02d", &nYear, &nMonth,
5✔
665
                  &nDay, &nHour, &nMinute, &nSecond);
666
    if (nRet >= 3)
5✔
667
    {
668
        return nRet;
5✔
669
    }
670
    return 0;
×
671
}
672

673
/************************************************************************/
674
/*                          IsSimpleComparison()                        */
675
/************************************************************************/
676

677
bool GDALEEDALayer::IsSimpleComparison(const swq_expr_node *poNode)
14✔
678
{
679
    return poNode->eNodeType == SNT_OPERATION &&
28✔
680
           (poNode->nOperation == SWQ_EQ || poNode->nOperation == SWQ_NE ||
14✔
681
            poNode->nOperation == SWQ_LT || poNode->nOperation == SWQ_LE ||
10✔
682
            poNode->nOperation == SWQ_GT || poNode->nOperation == SWQ_GE) &&
7✔
683
           poNode->nSubExprCount == 2 &&
11✔
684
           poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
11✔
685
           poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
39✔
686
           m_oSetQueryableFields.find(poNode->papoSubExpr[0]->field_index) !=
11✔
687
               m_oSetQueryableFields.end();
25✔
688
}
689

690
/************************************************************************/
691
/*                             GetOperatorText()                        */
692
/************************************************************************/
693

694
static const char *GetOperatorText(swq_op nOp)
6✔
695
{
696
    if (nOp == SWQ_LT)
6✔
697
        return "<";
1✔
698
    if (nOp == SWQ_LE)
5✔
699
        return "<=";
1✔
700
    if (nOp == SWQ_GT)
4✔
701
        return ">";
1✔
702
    if (nOp == SWQ_GE)
3✔
703
        return ">=";
1✔
704
    if (nOp == SWQ_EQ)
2✔
705
        return "=";
1✔
706
    if (nOp == SWQ_NE)
1✔
707
        return "!=";
1✔
708
    CPLAssert(false);
×
709
    return "";
710
}
711

712
/************************************************************************/
713
/*                             BuildFilter()                            */
714
/************************************************************************/
715

716
CPLString GDALEEDALayer::BuildFilter(swq_expr_node *poNode, bool bIsAndTopLevel)
26✔
717
{
718
    int nYear, nMonth, nDay, nHour, nMinute, nSecond;
719

720
    if (poNode->eNodeType == SNT_OPERATION && poNode->nOperation == SWQ_AND &&
26✔
721
        poNode->nSubExprCount == 2)
10✔
722
    {
723
        // For AND, we can deal with a failure in one of the branch
724
        // since client-side will do that extra filtering
725
        CPLString osLeft = BuildFilter(poNode->papoSubExpr[0], bIsAndTopLevel);
20✔
726
        CPLString osRight = BuildFilter(poNode->papoSubExpr[1], bIsAndTopLevel);
20✔
727
        if (!osLeft.empty() && !osRight.empty())
10✔
728
        {
729
            return "(" + osLeft + " AND " + osRight + ")";
14✔
730
        }
731
        else if (!osLeft.empty())
3✔
732
            return osLeft;
×
733
        else
734
            return osRight;
3✔
735
    }
736
    else if (poNode->eNodeType == SNT_OPERATION &&
16✔
737
             poNode->nOperation == SWQ_OR && poNode->nSubExprCount == 2)
16✔
738
    {
739
        // For OR, we need both members to be valid
740
        CPLString osLeft = BuildFilter(poNode->papoSubExpr[0], false);
2✔
741
        CPLString osRight = BuildFilter(poNode->papoSubExpr[1], false);
2✔
742
        if (!osLeft.empty() && !osRight.empty())
1✔
743
        {
744
            return "(" + osLeft + " OR " + osRight + ")";
2✔
745
        }
746
        return "";
×
747
    }
748
    else if (poNode->eNodeType == SNT_OPERATION &&
15✔
749
             poNode->nOperation == SWQ_NOT && poNode->nSubExprCount == 1)
15✔
750
    {
751
        CPLString osFilter = BuildFilter(poNode->papoSubExpr[0], false);
2✔
752
        if (!osFilter.empty())
1✔
753
        {
754
            return "(NOT " + osFilter + ")";
2✔
755
        }
756
        return "";
×
757
    }
758
    else if (IsSimpleComparison(poNode))
14✔
759
    {
760
        const int nFieldIdx = poNode->papoSubExpr[0]->field_index;
6✔
761
        CPLString osFilter(
762
            m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetNameRef());
12✔
763
        osFilter += " ";
6✔
764
        osFilter += GetOperatorText(poNode->nOperation);
6✔
765
        osFilter += " ";
6✔
766
        if (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER ||
6✔
767
            poNode->papoSubExpr[1]->field_type == SWQ_INTEGER64)
4✔
768
        {
769
            osFilter +=
4✔
770
                CPLSPrintf("%" PRId64, poNode->papoSubExpr[1]->int_value);
4✔
771
        }
772
        else if (poNode->papoSubExpr[1]->field_type == SWQ_FLOAT)
2✔
773
        {
774
            osFilter +=
775
                CPLSPrintf("%.17g", poNode->papoSubExpr[1]->float_value);
1✔
776
        }
777
        else
778
        {
779
            osFilter += "\"";
1✔
780
            osFilter += poNode->papoSubExpr[1]->string_value;
1✔
781
            osFilter += "\"";
1✔
782
        }
783
        return osFilter;
6✔
784
    }
785
    else if (bIsAndTopLevel && poNode->eNodeType == SNT_OPERATION &&
6✔
786
             (poNode->nOperation == SWQ_EQ || poNode->nOperation == SWQ_GE) &&
6✔
787
             poNode->nSubExprCount == 2 &&
4✔
788
             poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
4✔
789
             poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
4✔
790
             poNode->papoSubExpr[0]->field_index ==
4✔
791
                 m_poFeatureDefn->GetFieldIndex("startTime") &&
17✔
792
             poNode->papoSubExpr[1]->field_type == SWQ_TIMESTAMP)
3✔
793
    {
794
        int nTerms = GDALEEDALayerParseDateTime(
3✔
795
            poNode->papoSubExpr[1]->string_value, SWQ_GE, nYear, nMonth, nDay,
3✔
796
            nHour, nMinute, nSecond);
797
        if (nTerms >= 3)
3✔
798
        {
799
            m_osStartTime = CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", nYear,
800
                                       nMonth, nDay, nHour, nMinute, nSecond);
3✔
801
        }
802
        else
803
        {
804
            m_bFilterMustBeClientSideEvaluated = true;
×
805
        }
806
        return "";
3✔
807
    }
808
    else if (bIsAndTopLevel && poNode->eNodeType == SNT_OPERATION &&
3✔
809
             (poNode->nOperation == SWQ_EQ || poNode->nOperation == SWQ_LE) &&
3✔
810
             poNode->nSubExprCount == 2 &&
2✔
811
             poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
2✔
812
             poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
2✔
813
             poNode->papoSubExpr[0]->field_index ==
2✔
814
                 m_poFeatureDefn->GetFieldIndex("endTime") &&
10✔
815
             poNode->papoSubExpr[1]->field_type == SWQ_TIMESTAMP)
2✔
816
    {
817
        int nTerms = GDALEEDALayerParseDateTime(
2✔
818
            poNode->papoSubExpr[1]->string_value, SWQ_LE, nYear, nMonth, nDay,
2✔
819
            nHour, nMinute, nSecond);
820
        if (nTerms >= 3)
2✔
821
        {
822
            if (poNode->nOperation == SWQ_EQ && nTerms == 6)
2✔
823
            {
824
                if (nSecond < 59)
×
825
                    nSecond++;
×
826
                else if (nMinute < 59)
×
827
                    nMinute++;
×
828
                else if (nHour < 23)
×
829
                    nHour++;
×
830
                else
831
                    nDay++;
×
832
            }
833
            m_osEndTime = CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", nYear,
834
                                     nMonth, nDay, nHour, nMinute, nSecond);
2✔
835
        }
836
        else
837
        {
838
            m_bFilterMustBeClientSideEvaluated = true;
×
839
        }
840
        return "";
2✔
841
    }
842
    else if (poNode->eNodeType == SNT_OPERATION &&
9✔
843
             poNode->nOperation == SWQ_IN && poNode->nSubExprCount >= 2 &&
3✔
844
             poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
9✔
845
             m_oSetQueryableFields.find(poNode->papoSubExpr[0]->field_index) !=
3✔
846
                 m_oSetQueryableFields.end())
6✔
847
    {
848
        const int nFieldIdx = poNode->papoSubExpr[0]->field_index;
3✔
849
        CPLString osFilter;
6✔
850

851
        for (int i = 1; i < poNode->nSubExprCount; i++)
7✔
852
        {
853
            if (!osFilter.empty())
4✔
854
                osFilter += " OR ";
1✔
855
            osFilter += m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetNameRef();
4✔
856
            osFilter += " = ";
4✔
857
            if (poNode->papoSubExpr[i]->field_type == SWQ_INTEGER ||
4✔
858
                poNode->papoSubExpr[i]->field_type == SWQ_INTEGER64)
3✔
859
            {
860
                osFilter +=
1✔
861
                    CPLSPrintf("%" PRId64, poNode->papoSubExpr[i]->int_value);
1✔
862
            }
863
            else if (poNode->papoSubExpr[i]->field_type == SWQ_FLOAT)
3✔
864
            {
865
                osFilter +=
866
                    CPLSPrintf("%.17g", poNode->papoSubExpr[i]->float_value);
1✔
867
            }
868
            else
869
            {
870
                osFilter += "\"";
2✔
871
                osFilter += poNode->papoSubExpr[i]->string_value;
2✔
872
                osFilter += "\"";
2✔
873
            }
874
        }
875

876
        return osFilter;
3✔
877
    }
878

879
    m_bFilterMustBeClientSideEvaluated = true;
×
880
    return "";
×
881
}
882

883
/************************************************************************/
884
/*                         SetAttributeFilter()                         */
885
/************************************************************************/
886

887
OGRErr GDALEEDALayer::SetAttributeFilter(const char *pszQuery)
5✔
888

889
{
890
    m_osAttributeFilter.clear();
5✔
891
    m_osStartTime.clear();
5✔
892
    m_osEndTime.clear();
5✔
893
    m_bFilterMustBeClientSideEvaluated = false;
5✔
894

895
    if (pszQuery && STARTS_WITH_CI(pszQuery, "EEDA:"))
5✔
896
    {
897
        m_osAttributeFilter = pszQuery + strlen("EEDA:");
1✔
898
        OGRLayer::SetAttributeFilter(nullptr);
1✔
899
        ResetReading();
1✔
900
        return OGRERR_NONE;
1✔
901
    }
902

903
    OGRErr eErr = OGRLayer::SetAttributeFilter(pszQuery);
4✔
904

905
    if (m_poAttrQuery != nullptr)
4✔
906
    {
907
        swq_expr_node *poNode =
908
            static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
3✔
909

910
#ifndef PLUGIN
911
        poNode->ReplaceBetweenByGEAndLERecurse();
3✔
912
#endif
913

914
        m_osAttributeFilter = BuildFilter(poNode, true);
3✔
915
        if (m_osAttributeFilter.empty() && m_osStartTime.empty() &&
3✔
916
            m_osEndTime.empty())
×
917
        {
918
            CPLDebug("EEDA", "Full filter will be evaluated on client side.");
×
919
        }
920
        else if (m_bFilterMustBeClientSideEvaluated)
3✔
921
        {
922
            CPLDebug(
×
923
                "EEDA",
924
                "Only part of the filter will be evaluated on server side.");
925
        }
926
    }
927

928
    ResetReading();
4✔
929

930
    return eErr;
4✔
931
}
932

933
/************************************************************************/
934
/*                          ISetSpatialFilter()                         */
935
/************************************************************************/
936

937
OGRErr GDALEEDALayer::ISetSpatialFilter(int /* iGeomField */,
2✔
938
                                        const OGRGeometry *poGeomIn)
939
{
940
    if (poGeomIn)
2✔
941
    {
942
        OGREnvelope sEnvelope;
1✔
943
        poGeomIn->getEnvelope(&sEnvelope);
1✔
944
        if (sEnvelope.MinX == sEnvelope.MaxX &&
1✔
945
            sEnvelope.MinY == sEnvelope.MaxY)
×
946
        {
947
            OGRPoint p(sEnvelope.MinX, sEnvelope.MinY);
×
948
            InstallFilter(&p);
×
949
        }
950
        else
951
            InstallFilter(poGeomIn);
1✔
952
    }
953
    else
954
        InstallFilter(poGeomIn);
1✔
955

956
    ResetReading();
2✔
957
    return OGRERR_NONE;
2✔
958
}
959

960
/************************************************************************/
961
/*                                GetExtent()                           */
962
/************************************************************************/
963

964
OGRErr GDALEEDALayer::IGetExtent(int /* iGeomField*/, OGREnvelope *psExtent,
1✔
965
                                 bool /* bForce */)
966
{
967
    psExtent->MinX = -180;
1✔
968
    psExtent->MinY = -90;
1✔
969
    psExtent->MaxX = 180;
1✔
970
    psExtent->MaxY = 90;
1✔
971
    return OGRERR_NONE;
1✔
972
}
973

974
/************************************************************************/
975
/*                              TestCapability()                        */
976
/************************************************************************/
977

978
int GDALEEDALayer::TestCapability(const char *pszCap)
5✔
979
{
980
    if (EQUAL(pszCap, OLCStringsAsUTF8))
5✔
981
        return TRUE;
4✔
982
    return FALSE;
1✔
983
}
984

985
/************************************************************************/
986
/*                         GDALEEDADataset()                           */
987
/************************************************************************/
988

989
GDALEEDADataset::GDALEEDADataset() : m_poLayer(nullptr)
7✔
990
{
991
}
7✔
992

993
/************************************************************************/
994
/*                        ~GDALEEDADataset()                            */
995
/************************************************************************/
996

997
GDALEEDADataset::~GDALEEDADataset()
14✔
998
{
999
    delete m_poLayer;
7✔
1000
}
14✔
1001

1002
/************************************************************************/
1003
/*                            GetLayer()                                */
1004
/************************************************************************/
1005

1006
OGRLayer *GDALEEDADataset::GetLayer(int idx)
7✔
1007
{
1008
    if (idx == 0)
7✔
1009
        return m_poLayer;
7✔
1010
    return nullptr;
×
1011
}
1012

1013
/************************************************************************/
1014
/*                            RunRequest()                              */
1015
/************************************************************************/
1016

1017
json_object *GDALEEDADataset::RunRequest(const CPLString &osURL)
13✔
1018
{
1019
    char **papszOptions = GetBaseHTTPOptions();
13✔
1020
    if (papszOptions == nullptr)
13✔
1021
        return nullptr;
×
1022
    CPLHTTPResult *psResult = EEDAHTTPFetch(osURL, papszOptions);
13✔
1023
    CSLDestroy(papszOptions);
13✔
1024
    if (psResult == nullptr)
13✔
1025
        return nullptr;
×
1026
    if (psResult->pszErrBuf != nullptr)
13✔
1027
    {
1028
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
×
1029
                 psResult->pabyData
×
1030
                     ? reinterpret_cast<const char *>(psResult->pabyData)
1031
                     : psResult->pszErrBuf);
1032
        CPLHTTPDestroyResult(psResult);
×
1033
        return nullptr;
×
1034
    }
1035

1036
    if (psResult->pabyData == nullptr)
13✔
1037
    {
1038
        CPLError(CE_Failure, CPLE_AppDefined,
×
1039
                 "Empty content returned by server");
1040
        CPLHTTPDestroyResult(psResult);
×
1041
        return nullptr;
×
1042
    }
1043

1044
    const char *pszText = reinterpret_cast<const char *>(psResult->pabyData);
13✔
1045
#ifdef DEBUG_VERBOSE
1046
    CPLDebug("EEDA", "%s", pszText);
1047
#endif
1048

1049
    json_object *poObj = nullptr;
13✔
1050
    if (!OGRJSonParse(pszText, &poObj, true))
13✔
1051
    {
1052
        CPLHTTPDestroyResult(psResult);
×
1053
        return nullptr;
×
1054
    }
1055

1056
    CPLHTTPDestroyResult(psResult);
13✔
1057

1058
    if (json_object_get_type(poObj) != json_type_object)
13✔
1059
    {
1060
        CPLError(CE_Failure, CPLE_AppDefined,
×
1061
                 "Return is not a JSON dictionary");
1062
        json_object_put(poObj);
×
1063
        return nullptr;
×
1064
    }
1065

1066
    return poObj;
13✔
1067
}
1068

1069
/************************************************************************/
1070
/*                         GDALEEDADatasetGetConf()                     */
1071
/************************************************************************/
1072

1073
static json_object *GDALEEDADatasetGetConf()
7✔
1074
{
1075
    const char *pszConfFile = CPLFindFile("gdal", "eedaconf.json");
7✔
1076
    if (pszConfFile == nullptr)
7✔
1077
    {
1078
        CPLDebug("EEDA", "Cannot find eedaconf.json");
×
1079
        return nullptr;
×
1080
    }
1081

1082
    GByte *pabyRet = nullptr;
7✔
1083
    if (!VSIIngestFile(nullptr, pszConfFile, &pabyRet, nullptr, -1))
7✔
1084
    {
1085
        return nullptr;
×
1086
    }
1087

1088
    json_object *poRoot = nullptr;
7✔
1089
    const char *pzText = reinterpret_cast<char *>(pabyRet);
7✔
1090
    if (!OGRJSonParse(pzText, &poRoot))
7✔
1091
    {
1092
        VSIFree(pabyRet);
×
1093
        return nullptr;
×
1094
    }
1095
    VSIFree(pabyRet);
7✔
1096

1097
    if (json_object_get_type(poRoot) != json_type_object)
7✔
1098
    {
1099
        json_object_put(poRoot);
×
1100
        return nullptr;
×
1101
    }
1102

1103
    return poRoot;
7✔
1104
}
1105

1106
/************************************************************************/
1107
/*                               Open()                                 */
1108
/************************************************************************/
1109

1110
bool GDALEEDADataset::Open(GDALOpenInfo *poOpenInfo)
7✔
1111
{
1112
    m_osBaseURL = CPLGetConfigOption(
1113
        "EEDA_URL", "https://earthengine-highvolume.googleapis.com/v1alpha/");
7✔
1114

1115
    CPLString osCollection =
1116
        CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "COLLECTION", "");
14✔
1117
    if (osCollection.empty())
7✔
1118
    {
1119
        char **papszTokens =
1120
            CSLTokenizeString2(poOpenInfo->pszFilename, ":", 0);
7✔
1121
        if (CSLCount(papszTokens) < 2)
7✔
1122
        {
1123
            CPLError(CE_Failure, CPLE_AppDefined,
×
1124
                     "No collection specified in connection string or "
1125
                     "COLLECTION open option");
1126
            CSLDestroy(papszTokens);
×
1127
            return false;
×
1128
        }
1129
        osCollection = papszTokens[1];
7✔
1130
        CSLDestroy(papszTokens);
7✔
1131
    }
1132
    CPLString osCollectionName = ConvertPathToName(osCollection);
14✔
1133

1134
    json_object *poRootConf = GDALEEDADatasetGetConf();
7✔
1135
    if (poRootConf)
7✔
1136
    {
1137
        json_object *poLayerConf =
1138
            CPL_json_object_object_get(poRootConf, osCollection);
7✔
1139
        if (poLayerConf != nullptr &&
8✔
1140
            json_object_get_type(poLayerConf) == json_type_object)
1✔
1141
        {
1142
            m_poLayer = new GDALEEDALayer(this, osCollection, osCollectionName,
1✔
1143
                                          nullptr, poLayerConf);
1✔
1144
            json_object_put(poRootConf);
1✔
1145
            return true;
1✔
1146
        }
1147
        json_object_put(poRootConf);
6✔
1148
    }
1149

1150
    // Issue request to get layer schema
1151
    json_object *poRootAsset =
1152
        RunRequest(m_osBaseURL + osCollectionName + ":listImages?pageSize=1");
6✔
1153
    if (poRootAsset == nullptr)
6✔
1154
        return false;
×
1155

1156
    json_object *poAssets = CPL_json_object_object_get(poRootAsset, "images");
6✔
1157
    if (poAssets == nullptr ||
12✔
1158
        json_object_get_type(poAssets) != json_type_array ||
12✔
1159
        json_object_array_length(poAssets) != 1)
6✔
1160
    {
1161
        CPLError(CE_Failure, CPLE_AppDefined, "No assets");
×
1162
        json_object_put(poRootAsset);
×
1163
        return false;
×
1164
    }
1165
    json_object *poAsset = json_object_array_get_idx(poAssets, 0);
6✔
1166
    if (poAsset == nullptr || json_object_get_type(poAsset) != json_type_object)
6✔
1167
    {
1168
        CPLError(CE_Failure, CPLE_AppDefined, "No assets");
×
1169
        json_object_put(poRootAsset);
×
1170
        return false;
×
1171
    }
1172

1173
    m_poLayer = new GDALEEDALayer(this, osCollection, osCollectionName, poAsset,
6✔
1174
                                  nullptr);
6✔
1175
    json_object_put(poRootAsset);
6✔
1176

1177
    return true;
6✔
1178
}
1179

1180
/************************************************************************/
1181
/*                          GDALEEDAdentify()                          */
1182
/************************************************************************/
1183

1184
static int GDALEEDAdentify(GDALOpenInfo *poOpenInfo)
59,535✔
1185
{
1186
    return STARTS_WITH_CI(poOpenInfo->pszFilename, "EEDA:");
59,535✔
1187
}
1188

1189
/************************************************************************/
1190
/*                            GDALEEDAOpen()                            */
1191
/************************************************************************/
1192

1193
static GDALDataset *GDALEEDAOpen(GDALOpenInfo *poOpenInfo)
7✔
1194
{
1195
    if (!GDALEEDAdentify(poOpenInfo) || poOpenInfo->eAccess == GA_Update)
7✔
1196
        return nullptr;
×
1197

1198
    GDALEEDADataset *poDS = new GDALEEDADataset();
7✔
1199
    if (!poDS->Open(poOpenInfo))
7✔
1200
    {
1201
        delete poDS;
×
1202
        return nullptr;
×
1203
    }
1204
    return poDS;
7✔
1205
}
1206

1207
/************************************************************************/
1208
/*                         GDALRegister_EEDA()                          */
1209
/************************************************************************/
1210

1211
void GDALRegister_EEDA()
1,911✔
1212

1213
{
1214
    if (GDALGetDriverByName("EEDA") != nullptr)
1,911✔
1215
        return;
282✔
1216

1217
    GDALDriver *poDriver = new GDALDriver();
1,629✔
1218

1219
    poDriver->SetDescription("EEDA");
1,629✔
1220
    poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
1,629✔
1221
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Earth Engine Data API");
1,629✔
1222
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/eeda.html");
1,629✔
1223
    poDriver->SetMetadataItem(GDAL_DMD_CONNECTION_PREFIX, "EEDA:");
1,629✔
1224
    poDriver->SetMetadataItem(
1,629✔
1225
        GDAL_DMD_OPENOPTIONLIST,
1226
        "<OpenOptionList>"
1227
        "  <Option name='COLLECTION' type='string' "
1228
        "description='Collection name'/>"
1229
        "  <Option name='VSI_PATH_FOR_AUTH' type='string' "
1230
        "description='/vsigs/... path onto which a "
1231
        "GOOGLE_APPLICATION_CREDENTIALS path specific "
1232
        "option is set'/>"
1233
        "</OpenOptionList>");
1,629✔
1234

1235
    poDriver->pfnOpen = GDALEEDAOpen;
1,629✔
1236
    poDriver->pfnIdentify = GDALEEDAdentify;
1,629✔
1237

1238
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
1239

1240
#ifdef GDAL_ENABLE_DRIVER_EEDA_PLUGIN
1241
    GDALRegister_EEDAI();
1242
#endif
1243
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc