Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdal_rat.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  GDALRasterAttributeTable class declarations.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#ifndef GDAL_RAT_H_INCLUDED
14
#define GDAL_RAT_H_INCLUDED
15
16
#if !defined(GDAL_COMPILATION) &&                                              \
17
    !defined(GDAL_RAT_SKIP_OTHER_GDAL_HEADERS) && !defined(GDAL_4_0_COMPAT)
18
19
#include "cpl_minixml.h"
20
#include "gdal_priv.h"
21
22
#else
23
24
#include "cpl_port.h"
25
#include "cpl_error.h"
26
#include "cpl_string.h"
27
#include "gdal.h"
28
29
#endif
30
31
#include <memory>
32
#include <vector>
33
34
class GDALColorTable;
35
36
// Clone and Serialize are allowed to fail if GetRowCount()*GetColCount()
37
// greater than this number
38
#define RAT_MAX_ELEM_FOR_CLONE 1000000
39
40
/************************************************************************/
41
/*                       GDALRasterAttributeTable                       */
42
/************************************************************************/
43
44
//! Raster Attribute Table interface.
45
class GDALDefaultRasterAttributeTable;
46
47
class CPL_DLL GDALRasterAttributeTable
48
{
49
  public:
50
    virtual ~GDALRasterAttributeTable();
51
    /**
52
     * \brief Copy Raster Attribute Table
53
     *
54
     * Creates a new copy of an existing raster attribute table.  The new copy
55
     * becomes the responsibility of the caller to destroy.
56
     * May fail (return nullptr) if the attribute table is too large to clone
57
     * (GetRowCount() * GetColCount() > RAT_MAX_ELEM_FOR_CLONE)
58
     *
59
     * This method is the same as the C function GDALRATClone().
60
     *
61
     * @return new copy of the RAT as an in-memory implementation.
62
     */
63
    virtual GDALRasterAttributeTable *Clone() const = 0;
64
65
    /**
66
     * \brief Fetch table column count.
67
     *
68
     * This method is the same as the C function GDALRATGetColumnCount().
69
     *
70
     * @return the number of columns.
71
     */
72
    virtual int GetColumnCount() const = 0;
73
74
    /**
75
     * \brief Fetch name of indicated column.
76
     *
77
     * This method is the same as the C function GDALRATGetNameOfCol().
78
     *
79
     * @param iCol the column index (zero based).
80
     *
81
     * @return the column name or an empty string for invalid column numbers.
82
     */
83
    virtual const char *GetNameOfCol(int iCol) const = 0;
84
85
    /**
86
     * \brief Fetch column usage value.
87
     *
88
     * This method is the same as the C function GDALRATGetUsageOfCol().
89
     *
90
     * @param iCol the column index (zero based).
91
     *
92
     * @return the column usage, or GFU_Generic for improper column numbers.
93
     */
94
    virtual GDALRATFieldUsage GetUsageOfCol(int iCol) const = 0;
95
96
    /**
97
     * \brief Fetch column type.
98
     *
99
     * This method is the same as the C function GDALRATGetTypeOfCol().
100
     *
101
     * @param iCol the column index (zero based).
102
     *
103
     * @return column type or GFT_Integer if the column index is illegal.
104
     */
105
    virtual GDALRATFieldType GetTypeOfCol(int iCol) const = 0;
106
107
    /**
108
     * \brief Fetch column index for given usage.
109
     *
110
     * Returns the index of the first column of the requested usage type, or -1
111
     * if no match is found.
112
     *
113
     * This method is the same as the C function GDALRATGetUsageOfCol().
114
     *
115
     * @param eUsage usage type to search for.
116
     *
117
     * @return column index, or -1 on failure.
118
     */
119
    virtual int GetColOfUsage(GDALRATFieldUsage eUsage) const = 0;
120
121
    /**
122
     * \brief Fetch row count.
123
     *
124
     * This method is the same as the C function GDALRATGetRowCount().
125
     *
126
     * @return the number of rows.
127
     */
128
    virtual int GetRowCount() const = 0;
129
130
    /**
131
     * \brief Fetch field value as a string.
132
     *
133
     * The value of the requested column in the requested row is returned
134
     * as a string. This method is nominally called on fields of type GFT_String,
135
     * but it can be called on fields of other types as well.
136
     * If the field is numeric, it is formatted as a string
137
     * using default rules, so some precision may be lost.
138
     *
139
     * The returned string is temporary and cannot be expected to be
140
     * available after the next GDAL call.
141
     *
142
     * This method is the same as the C function GDALRATGetValueAsString().
143
     *
144
     * @param iRow row to fetch (zero based).
145
     * @param iField column to fetch (zero based).
146
     *
147
     * @return field value.
148
     */
149
    virtual const char *GetValueAsString(int iRow, int iField) const = 0;
150
151
    /**
152
     * \brief Fetch field value as a integer.
153
     *
154
     * The value of the requested column in the requested row is returned
155
     * as an integer. This method is nominally called on fields of type
156
     * GFT_Integer, but it can be called on fields of other types as well.
157
     * Non-integer fields will be converted to integer with the possibility of
158
     * data loss.
159
     *
160
     * This method is the same as the C function GDALRATGetValueAsInt().
161
     *
162
     * @param iRow row to fetch (zero based).
163
     * @param iField column to fetch (zero based).
164
     *
165
     * @return field value
166
     */
167
    virtual int GetValueAsInt(int iRow, int iField) const = 0;
168
169
    /**
170
     * \brief Fetch field value as a double.
171
     *
172
     * The value of the requested column in the requested row is returned
173
     * as a double. This method is nominally called on fields of type
174
     * GFT_Real, but it can be called on fields of other types as well.
175
     * Non double fields will be converted to double with
176
     * the possibility of data loss.
177
     *
178
     * This method is the same as the C function GDALRATGetValueAsDouble().
179
     *
180
     * @param iRow row to fetch (zero based).
181
     * @param iField column to fetch (zero based).
182
     *
183
     * @return field value
184
     */
185
    virtual double GetValueAsDouble(int iRow, int iField) const = 0;
186
187
    /**
188
     * \brief Fetch field value as a boolean.
189
     *
190
     * The value of the requested column in the requested row is returned
191
     * as a boolean. This method is nominally called on fields of type
192
     * GFT_Boolean, but it can be called on fields of other types as well.
193
     * Non boolean fields will be converted to boolean with the possibility of
194
     * data loss.
195
     *
196
     * This method is the same as the C function GDALRATGetValueAsBoolean().
197
     *
198
     * @param iRow row to fetch (zero based).
199
     * @param iField column to fetch (zero based).
200
     *
201
     * @return field value
202
     * @since 3.12
203
     */
204
    virtual bool GetValueAsBoolean(int iRow, int iField) const = 0;
205
206
    /**
207
     * \brief Fetch field value as a datetime.
208
     *
209
     * The value of the requested column in the requested row is returned
210
     * as a datetime. Besides being called on a GFT_DateTime field, it
211
     * is also possible to call this method on a string field that contains a
212
     * ISO-8601 encoded datetime.
213
     *
214
     * This method is the same as the C function GDALRATGetValueAsDateTime().
215
     *
216
     * @param iRow row to fetch (zero based).
217
     * @param iField column to fetch (zero based).
218
     *
219
     * @return field value
220
     * @since 3.12
221
     */
222
    virtual GDALRATDateTime GetValueAsDateTime(int iRow, int iField) const = 0;
223
224
    /**
225
     * \brief Fetch field value as a WKB geometry.
226
     *
227
     * The value of the requested column in the requested row is returned
228
     * as a WKB geometry. Besides being called on a GFT_WKBGeometry field, it
229
     * is also possible to call this method on a string field that contains a WKT
230
     * encoded geometry.
231
     *
232
     * The returned pointer may be invalidated by a following call to a method
233
     * of this GDALRasterAttributeTable instance.
234
     *
235
     * This method is the same as the C function GDALRATGetValueAsWKBGeometry().
236
     *
237
     * @param iRow row to fetch (zero based).
238
     * @param iField column to fetch (zero based).
239
     * @param[out] nWKBSize Number of bytes of the returned pointer
240
     * @return field value, or nullptr
241
     * @since 3.12
242
     */
243
    virtual const GByte *GetValueAsWKBGeometry(int iRow, int iField,
244
                                               size_t &nWKBSize) const = 0;
245
246
    /**
247
     * \brief Set field value from string.
248
     *
249
     * The indicated field (column) on the indicated row is set from the
250
     * passed value. This method is nominally called on fields of type
251
     * GFT_String, but it can be called on fields of other types as well.
252
     * The value will be automatically converted for other field
253
     * types, with a possible loss of precision.
254
     *
255
     * This method is the same as the C function GDALRATSetValueAsString().
256
     *
257
     * @param iRow row to fetch (zero based).
258
     * @param iField column to fetch (zero based).
259
     * @param pszValue the value to assign.
260
     * @return (since 3.12) CE_None in case of success, error code otherwise
261
     */
262
    virtual CPLErr SetValue(int iRow, int iField, const char *pszValue) = 0;
263
264
    /**
265
     * \brief Set field value from integer.
266
     *
267
     * The indicated field (column) on the indicated row is set from the
268
     * passed value. This method is nominally called on fields of type
269
     * GFT_Integer, but it can be called on fields of other types as well.
270
     * The value will be automatically converted for other field
271
     * types, with a possible loss of precision.
272
     *
273
     * This method is the same as the C function GDALRATSetValueAsInteger().
274
     *
275
     * @param iRow row to fetch (zero based).
276
     * @param iField column to fetch (zero based).
277
     * @param nValue the value to assign.
278
     * @return (since 3.12) CE_None in case of success, error code otherwise
279
     */
280
    virtual CPLErr SetValue(int iRow, int iField, int nValue) = 0;
281
282
    /**
283
     * \brief Set field value from double.
284
     *
285
     * The indicated field (column) on the indicated row is set from the
286
     * passed value. This method is nominally called on fields of type
287
     * GFT_Real, but it can be called on fields of other types as well.
288
     * The value will be automatically converted for other field
289
     * types, with a possible loss of precision.
290
     *
291
     * This method is the same as the C function GDALRATSetValueAsDouble().
292
     *
293
     * @param iRow row to fetch (zero based).
294
     * @param iField column to fetch (zero based).
295
     * @param dfValue the value to assign.
296
     * @return (since 3.12) CE_None in case of success, error code otherwise
297
     */
298
    virtual CPLErr SetValue(int iRow, int iField, double dfValue) = 0;
299
300
    /**
301
     * \brief Set field value from boolean.
302
     *
303
     * The indicated field (column) on the indicated row is set from the
304
     * passed value.  This method is nominally called on fields of type
305
     * GFT_Boolean, but it can be called on fields of other types as well.
306
     * The value will be automatically converted for other field
307
     * types, with a possible loss of precision.
308
     *
309
     * This method is the same as the C function GDALRATSetValueAsBoolean().
310
     *
311
     * @param iRow row to fetch (zero based).
312
     * @param iField column to fetch (zero based).
313
     * @param bValue the value to assign.
314
     * @return CE_None in case of success, error code otherwise
315
     * @since 3.12
316
     */
317
    virtual CPLErr SetValue(int iRow, int iField, bool bValue) = 0;
318
319
    /**
320
     * \brief Set field value from datetime.
321
     *
322
     * The indicated field (column) on the indicated row is set from the
323
     * passed value. Besides being called on a field of type GFT_DateTime, this
324
     * method can also be called on a field of type GFT_String, in which case
325
     * the datetime will be converted into its ISO-8601 representation.
326
     *
327
     * Note that the GDALRATDateTime::bIsValid field must be set to true if
328
     * the date time is valid.
329
     *
330
     * This method is the same as the C function GDALRATSetValueAsDateTime().
331
     *
332
     * @param iRow row to fetch (zero based).
333
     * @param iField column to fetch (zero based).
334
     * @param sDateTime Date time value
335
     * @return CE_None in case of success, error code otherwise
336
     * @since 3.12
337
     */
338
    virtual CPLErr SetValue(int iRow, int iField,
339
                            const GDALRATDateTime &sDateTime) = 0;
340
341
    /**
342
     * \brief Set field value from a WKB geometry.
343
     *
344
     * The indicated field (column) on the indicated row is set from the
345
     * passed value. Besides being called on a field of type GFT_WKBGeometry, this
346
     * method can also be called on a field of type GFT_String, in which case
347
     * the datetime will be converted into its WKT geometry representation.
348
     *
349
     * This method is the same as the C function GDALRATSetValueAsWKBGeometry().
350
     *
351
     * @param iRow row to fetch (zero based).
352
     * @param iField column to fetch (zero based).
353
     * @param pabyWKB Pointer to a WKB encoded geometry
354
     * @param nWKBSize Number of bytes of pabyWKB.
355
     * @return CE_None in case of success, error code otherwise
356
     * @since 3.12
357
     */
358
    virtual CPLErr SetValue(int iRow, int iField, const void *pabyWKB,
359
                            size_t nWKBSize) = 0;
360
361
    /**
362
     * \brief Determine whether changes made to this RAT are reflected directly
363
     * in the dataset
364
     *
365
     * If this returns FALSE then GDALRasterBand.SetDefaultRAT() should be
366
     * called. Otherwise this is unnecessary since changes to this object are
367
     * reflected in the dataset.
368
     *
369
     * This method is the same as the C function
370
     * GDALRATChangesAreWrittenToFile().
371
     *
372
     */
373
    virtual int ChangesAreWrittenToFile() = 0;
374
375
    /**
376
     * \brief Set the RAT table type.
377
     *
378
     * Set whether the RAT is thematic or athematic (continuous).
379
     *
380
     */
381
    virtual CPLErr SetTableType(const GDALRATTableType eInTableType) = 0;
382
383
    /**
384
     * \brief Get the RAT table type.
385
     *
386
     * Indicates whether the RAT is thematic or athematic (continuous).
387
     *
388
     * @return table type
389
     */
390
    virtual GDALRATTableType GetTableType() const = 0;
391
392
    virtual CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow,
393
                            int iLength, double *pdfData);
394
    virtual CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow,
395
                            int iLength, int *pnData);
396
    virtual CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow,
397
                            int iLength, char **papszStrList);
398
    virtual CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow,
399
                            int iLength, bool *pbData);
400
    virtual CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow,
401
                            int iLength, GDALRATDateTime *pasDateTime);
402
    virtual CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow,
403
                            int iLength, GByte **ppabyWKB, size_t *pnWKBSize);
404
405
    virtual void SetRowCount(int iCount);
406
    virtual int GetRowOfValue(double dfValue) const;
407
    virtual int GetRowOfValue(int nValue) const;
408
409
    virtual CPLErr CreateColumn(const char *pszFieldName,
410
                                GDALRATFieldType eFieldType,
411
                                GDALRATFieldUsage eFieldUsage);
412
    virtual CPLErr SetLinearBinning(double dfRow0Min, double dfBinSize);
413
    virtual int GetLinearBinning(double *pdfRow0Min, double *pdfBinSize) const;
414
415
    /**
416
     * \brief Serialize
417
     *
418
     * May fail (return nullptr) if the attribute table is too large to
419
     * serialize (GetRowCount() * GetColCount() > RAT_MAX_ELEM_FOR_CLONE)
420
     */
421
    virtual CPLXMLNode *Serialize() const;
422
    virtual void *SerializeJSON() const;
423
    virtual CPLErr XMLInit(const CPLXMLNode *, const char *);
424
425
    virtual CPLErr InitializeFromColorTable(const GDALColorTable *);
426
    virtual GDALColorTable *TranslateToColorTable(int nEntryCount = -1);
427
428
    virtual void DumpReadable(FILE * = nullptr);
429
430
    /** Convert a GDALRasterAttributeTable* to a GDALRasterAttributeTableH.
431
     */
432
    static inline GDALRasterAttributeTableH
433
    ToHandle(GDALRasterAttributeTable *poRAT)
434
0
    {
435
0
        return static_cast<GDALRasterAttributeTableH>(poRAT);
436
0
    }
437
438
    /** Convert a GDALRasterAttributeTableH to a GDALRasterAttributeTable*.
439
     */
440
    static inline GDALRasterAttributeTable *
441
    FromHandle(GDALRasterAttributeTableH hRAT)
442
0
    {
443
0
        return static_cast<GDALRasterAttributeTable *>(hRAT);
444
0
    }
445
446
    /**
447
     * \brief Remove statistics from the RAT.
448
     *
449
     */
450
    virtual void RemoveStatistics() = 0;
451
452
    //! @cond Doxygen_Suppress
453
    static std::string DateTimeToString(const GDALRATDateTime &sDateTime);
454
    static bool StringToDateTime(const char *pszStr,
455
                                 GDALRATDateTime &sDateTime);
456
457
    static std::string WKBGeometryToWKT(const void *pabyWKB, size_t nWKBSize);
458
    static std::vector<GByte> WKTGeometryToWKB(const char *pszWKT);
459
    //! @endcond
460
461
  protected:
462
    //! @cond Doxygen_Suppress
463
0
    GDALRasterAttributeTable() = default;
464
0
    GDALRasterAttributeTable(const GDALRasterAttributeTable &) = default;
465
    GDALRasterAttributeTable &
466
    operator=(const GDALRasterAttributeTable &) = default;
467
    GDALRasterAttributeTable(GDALRasterAttributeTable &&) = default;
468
    GDALRasterAttributeTable &operator=(GDALRasterAttributeTable &&) = default;
469
470
    CPLErr ValuesIOBooleanFromIntoInt(GDALRWFlag eRWFlag, int iField,
471
                                      int iStartRow, int iLength, bool *pbData);
472
    CPLErr ValuesIODateTimeFromIntoString(GDALRWFlag eRWFlag, int iField,
473
                                          int iStartRow, int iLength,
474
                                          GDALRATDateTime *psDateTime);
475
    CPLErr ValuesIOWKBGeometryFromIntoString(GDALRWFlag eRWFlag, int iField,
476
                                             int iStartRow, int iLength,
477
                                             GByte **ppabyWKB,
478
                                             size_t *pnWKBSize);
479
    //! @endcond
480
};
481
482
/************************************************************************/
483
/*                    GDALDefaultRasterAttributeTable                   */
484
/************************************************************************/
485
486
//! Raster Attribute Table container.
487
488
class CPL_DLL GDALDefaultRasterAttributeTable : public GDALRasterAttributeTable
489
{
490
  private:
491
    struct GDALRasterAttributeField
492
    {
493
        CPLString sName{};
494
495
        GDALRATFieldType eType = GFT_Integer;
496
497
        GDALRATFieldUsage eUsage = GFU_Generic;
498
499
        std::vector<GInt32> anValues{};
500
        std::vector<double> adfValues{};
501
        std::vector<CPLString> aosValues{};
502
        std::vector<bool> abValues{};
503
        std::vector<GDALRATDateTime> asDateTimeValues{};
504
        std::vector<std::vector<GByte>> aabyWKBGeometryValues{};
505
    };
506
507
    std::vector<GDALRasterAttributeField> aoFields{};
508
509
    int bLinearBinning = false;  // TODO(schwehr): Can this be a bool?
510
    double dfRow0Min = -0.5;
511
    double dfBinSize = 1.0;
512
513
    GDALRATTableType eTableType = GRTT_THEMATIC;
514
515
    void AnalyseColumns();
516
    int bColumnsAnalysed = false;  // TODO(schwehr): Can this be a bool?
517
    int nMinCol = -1;
518
    int nMaxCol = -1;
519
520
    int nRowCount = 0;
521
522
    CPLString osWorkingResult{};
523
    mutable std::vector<GByte> m_abyWKB{};
524
525
  public:
526
    GDALDefaultRasterAttributeTable();
527
    ~GDALDefaultRasterAttributeTable() override;
528
529
    //! @cond Doxygen_Suppress
530
    GDALDefaultRasterAttributeTable(const GDALDefaultRasterAttributeTable &) =
531
0
        default;
532
    GDALDefaultRasterAttributeTable &
533
    operator=(const GDALDefaultRasterAttributeTable &) = default;
534
    GDALDefaultRasterAttributeTable(GDALDefaultRasterAttributeTable &&) =
535
        default;
536
    GDALDefaultRasterAttributeTable &
537
    operator=(GDALDefaultRasterAttributeTable &&) = default;
538
    //! @endcond
539
540
    GDALDefaultRasterAttributeTable *Clone() const override;
541
542
    int GetColumnCount() const override;
543
544
    const char *GetNameOfCol(int) const override;
545
    GDALRATFieldUsage GetUsageOfCol(int) const override;
546
    GDALRATFieldType GetTypeOfCol(int) const override;
547
548
    int GetColOfUsage(GDALRATFieldUsage) const override;
549
550
    int GetRowCount() const override;
551
552
    const char *GetValueAsString(int iRow, int iField) const override;
553
    int GetValueAsInt(int iRow, int iField) const override;
554
    double GetValueAsDouble(int iRow, int iField) const override;
555
    bool GetValueAsBoolean(int iRow, int iField) const override;
556
    GDALRATDateTime GetValueAsDateTime(int iRow, int iField) const override;
557
    const GByte *GetValueAsWKBGeometry(int iRow, int iField,
558
                                       size_t &nWKBSize) const override;
559
560
    CPLErr SetValue(int iRow, int iField, const char *pszValue) override;
561
    CPLErr SetValue(int iRow, int iField, double dfValue) override;
562
    CPLErr SetValue(int iRow, int iField, int nValue) override;
563
    CPLErr SetValue(int iRow, int iField, bool bValue) override;
564
    CPLErr SetValue(int iRow, int iField,
565
                    const GDALRATDateTime &sDateTime) override;
566
    CPLErr SetValue(int iRow, int iField, const void *pabyWKB,
567
                    size_t nWKBSize) override;
568
569
    int ChangesAreWrittenToFile() override;
570
    void SetRowCount(int iCount) override;
571
572
    int GetRowOfValue(double dfValue) const override;
573
    int GetRowOfValue(int nValue) const override;
574
575
    CPLErr CreateColumn(const char *pszFieldName, GDALRATFieldType eFieldType,
576
                        GDALRATFieldUsage eFieldUsage) override;
577
    CPLErr SetLinearBinning(double dfRow0Min, double dfBinSize) override;
578
    int GetLinearBinning(double *pdfRow0Min, double *pdfBinSize) const override;
579
580
    CPLErr SetTableType(const GDALRATTableType eInTableType) override;
581
    GDALRATTableType GetTableType() const override;
582
583
    void RemoveStatistics() override;
584
};
585
586
std::unique_ptr<GDALRasterAttributeTable>
587
    CPL_DLL GDALLoadVATDBF(const char *pszFilename);
588
589
#endif /* ndef GDAL_RAT_H_INCLUDED */