LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ograrrowarrayhelper.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 219 295 74.2 %
Date: 2026-01-16 04:37:55 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Helper to fill ArrowArray
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2022, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ograrrowarrayhelper.h"
      14             : #include "ogrlayerarrow.h"
      15             : #include "ogr_p.h"
      16             : 
      17             : #include <limits>
      18             : 
      19             : //! @cond Doxygen_Suppress
      20             : 
      21             : /************************************************************************/
      22             : /*                           GetMemLimit()                              */
      23             : /************************************************************************/
      24             : 
      25        1730 : /*static*/ uint32_t OGRArrowArrayHelper::GetMemLimit()
      26             : {
      27        1730 :     uint32_t nMemLimit =
      28             :         static_cast<uint32_t>(std::numeric_limits<int32_t>::max());
      29             :     // Just for tests
      30             :     const char *pszOGR_ARROW_MEM_LIMIT =
      31        1730 :         CPLGetConfigOption("OGR_ARROW_MEM_LIMIT", nullptr);
      32        1730 :     if (pszOGR_ARROW_MEM_LIMIT)
      33         131 :         nMemLimit = atoi(pszOGR_ARROW_MEM_LIMIT);
      34             :     else
      35             :     {
      36        1599 :         const auto nUsableRAM = CPLGetUsablePhysicalRAM();
      37        1599 :         if (nUsableRAM > 0 && static_cast<uint64_t>(nUsableRAM / 4) < nMemLimit)
      38           0 :             nMemLimit = static_cast<uint32_t>(nUsableRAM / 4);
      39             :     }
      40        1730 :     return nMemLimit;
      41             : }
      42             : 
      43             : /************************************************************************/
      44             : /*                       GetMaxFeaturesInBatch()                        */
      45             : /************************************************************************/
      46             : 
      47             : /* static */
      48         572 : int OGRArrowArrayHelper::GetMaxFeaturesInBatch(
      49             :     const CPLStringList &aosArrowArrayStreamOptions)
      50             : {
      51         572 :     int l_nMaxBatchSize = atoi(aosArrowArrayStreamOptions.FetchNameValueDef(
      52             :         "MAX_FEATURES_IN_BATCH", "65536"));
      53         572 :     if (l_nMaxBatchSize <= 0)
      54           0 :         l_nMaxBatchSize = 1;
      55         572 :     if (l_nMaxBatchSize > INT_MAX - 1)
      56           0 :         l_nMaxBatchSize = INT_MAX - 1;
      57             : 
      58         572 :     return l_nMaxBatchSize;
      59             : }
      60             : 
      61             : /************************************************************************/
      62             : /*                       OGRArrowArrayHelper()                          */
      63             : /************************************************************************/
      64             : 
      65           8 : OGRArrowArrayHelper::OGRArrowArrayHelper(struct ArrowArray *out_array,
      66           8 :                                          int nMaxBatchSize)
      67           8 :     : m_nMaxBatchSize(nMaxBatchSize), m_out_array(out_array)
      68             : {
      69           8 :     m_anArrowFieldMaxAlloc.resize(static_cast<size_t>(out_array->n_children));
      70           8 : }
      71             : 
      72             : /************************************************************************/
      73             : /*                       OGRArrowArrayHelper()                          */
      74             : /************************************************************************/
      75             : 
      76         422 : OGRArrowArrayHelper::OGRArrowArrayHelper(
      77             :     GDALDataset *poDS, OGRFeatureDefn *poFeatureDefn,
      78             :     const CPLStringList &aosArrowArrayStreamOptions,
      79         422 :     struct ArrowArray *out_array)
      80         422 :     : m_bIncludeFID(CPLTestBool(
      81             :           aosArrowArrayStreamOptions.FetchNameValueDef("INCLUDE_FID", "YES"))),
      82         844 :       m_nMaxBatchSize(GetMaxFeaturesInBatch(aosArrowArrayStreamOptions)),
      83         844 :       m_nFieldCount(poFeatureDefn->GetFieldCount()),
      84         844 :       m_nGeomFieldCount(poFeatureDefn->GetGeomFieldCount()),
      85         422 :       m_out_array(out_array)
      86             : {
      87         422 :     memset(out_array, 0, sizeof(*out_array));
      88             : 
      89         422 :     m_mapOGRFieldToArrowField.resize(m_nFieldCount, -1);
      90         422 :     m_mapOGRGeomFieldToArrowField.resize(m_nGeomFieldCount, -1);
      91         422 :     m_abNullableFields.resize(m_nFieldCount);
      92         422 :     m_anTZFlags.resize(m_nFieldCount);
      93         422 :     int nTZFlagOverride = -1;
      94             :     const char *pszTZOverride =
      95         422 :         aosArrowArrayStreamOptions.FetchNameValue("TIMEZONE");
      96         422 :     if (pszTZOverride)
      97             :     {
      98         373 :         if (EQUAL(pszTZOverride, "unknown") || EQUAL(pszTZOverride, ""))
      99             :         {
     100           0 :             nTZFlagOverride = OGR_TZFLAG_UNKNOWN;
     101             :         }
     102         373 :         else if (EQUAL(pszTZOverride, "mixed"))
     103             :         {
     104           0 :             nTZFlagOverride = OGR_TZFLAG_MIXED_TZ;
     105             :         }
     106             :         else
     107             :         {
     108             :             // we don't really care about the actual timezone, since we
     109             :             // will convert OGRField::Date to UTC in all cases
     110         373 :             nTZFlagOverride = OGR_TZFLAG_UTC;
     111             :         }
     112             :     }
     113             :     const bool bDateTimeAsString =
     114         422 :         aosArrowArrayStreamOptions.FetchBool(GAS_OPT_DATETIME_AS_STRING, false);
     115             : 
     116         422 :     if (m_bIncludeFID)
     117             :     {
     118         410 :         m_nChildren++;
     119             :     }
     120             :     // cppcheck-suppress knownConditionTrueFalse
     121        3157 :     for (int i = 0; i < m_nFieldCount; i++)
     122             :     {
     123        2735 :         const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     124        2735 :         m_abNullableFields[i] = CPL_TO_BOOL(poFieldDefn->IsNullable());
     125        2735 :         m_anTZFlags[i] =
     126        2735 :             nTZFlagOverride >= 0 ? nTZFlagOverride : poFieldDefn->GetTZFlag();
     127        2735 :         if (!poFieldDefn->IsIgnored())
     128             :         {
     129        2696 :             m_mapOGRFieldToArrowField[i] = m_nChildren;
     130        2696 :             m_nChildren++;
     131             :         }
     132             :     }
     133             :     // cppcheck-suppress knownConditionTrueFalse
     134         839 :     for (int i = 0; i < m_nGeomFieldCount; i++)
     135             :     {
     136         417 :         if (!poFeatureDefn->GetGeomFieldDefn(i)->IsIgnored())
     137             :         {
     138         404 :             m_mapOGRGeomFieldToArrowField[i] = m_nChildren;
     139         404 :             m_nChildren++;
     140             :         }
     141             :     }
     142             : 
     143         422 :     m_anArrowFieldMaxAlloc.resize(m_nChildren);
     144             : 
     145         422 :     out_array->release = OGRLayer::ReleaseArray;
     146             : 
     147         422 :     out_array->length = m_nMaxBatchSize;
     148         422 :     out_array->null_count = 0;
     149             : 
     150         422 :     out_array->n_children = m_nChildren;
     151         422 :     out_array->children = static_cast<struct ArrowArray **>(
     152         422 :         CPLCalloc(m_nChildren, sizeof(struct ArrowArray *)));
     153         422 :     out_array->release = OGRLayer::ReleaseArray;
     154         422 :     out_array->n_buffers = 1;
     155         422 :     out_array->buffers =
     156         422 :         static_cast<const void **>(CPLCalloc(1, sizeof(void *)));
     157             : 
     158             :     // Allocate buffers
     159             : 
     160         422 :     if (m_bIncludeFID)
     161             :     {
     162         820 :         out_array->children[0] = static_cast<struct ArrowArray *>(
     163         410 :             CPLCalloc(1, sizeof(struct ArrowArray)));
     164         410 :         auto psChild = out_array->children[0];
     165         410 :         psChild->release = OGRLayer::ReleaseArray;
     166         410 :         psChild->length = m_nMaxBatchSize;
     167         410 :         psChild->n_buffers = 2;
     168         410 :         psChild->buffers =
     169         410 :             static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
     170         410 :         m_panFIDValues = static_cast<int64_t *>(
     171         410 :             VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(int64_t) * m_nMaxBatchSize));
     172         410 :         if (m_panFIDValues == nullptr)
     173           0 :             goto error;
     174         410 :         psChild->buffers[1] = m_panFIDValues;
     175             :     }
     176             : 
     177             :     // cppcheck-suppress knownConditionTrueFalse
     178        3157 :     for (int i = 0; i < m_nFieldCount; i++)
     179             :     {
     180        2735 :         const int iArrowField = m_mapOGRFieldToArrowField[i];
     181        2735 :         if (iArrowField >= 0)
     182             :         {
     183        2696 :             const auto poFieldDefn = poFeatureDefn->GetFieldDefn(i);
     184        5392 :             out_array->children[iArrowField] = static_cast<struct ArrowArray *>(
     185        2696 :                 CPLCalloc(1, sizeof(struct ArrowArray)));
     186        2696 :             auto psChild = out_array->children[iArrowField];
     187             : 
     188        2696 :             psChild->release = OGRLayer::ReleaseArray;
     189        2696 :             psChild->length = m_nMaxBatchSize;
     190        2696 :             const auto eSubType = poFieldDefn->GetSubType();
     191        2696 :             size_t nEltSize = 0;
     192        2696 :             switch (poFieldDefn->GetType())
     193             :             {
     194        1712 :                 case OFTInteger:
     195             :                 {
     196        1712 :                     if (eSubType == OFSTBoolean)
     197             :                     {
     198          65 :                         nEltSize = sizeof(uint8_t);
     199             :                     }
     200        1647 :                     else if (eSubType == OFSTInt16)
     201             :                     {
     202          61 :                         nEltSize = sizeof(int16_t);
     203             :                     }
     204             :                     else
     205             :                     {
     206        1586 :                         nEltSize = sizeof(int32_t);
     207             :                     }
     208             : 
     209        1712 :                     const auto &osDomainName = poFieldDefn->GetDomainName();
     210        1712 :                     if (!osDomainName.empty() && poDS != nullptr)
     211             :                     {
     212             :                         const auto poFieldDomain =
     213          24 :                             poDS->GetFieldDomain(osDomainName);
     214          48 :                         if (poFieldDomain &&
     215          24 :                             poFieldDomain->GetDomainType() == OFDT_CODED)
     216             :                         {
     217          24 :                             const OGRCodedFieldDomain *poCodedDomain =
     218             :                                 static_cast<const OGRCodedFieldDomain *>(
     219             :                                     poFieldDomain);
     220          24 :                             FillDict(psChild, poCodedDomain);
     221             :                         }
     222             :                     }
     223             : 
     224        1712 :                     break;
     225             :                 }
     226          87 :                 case OFTInteger64:
     227             :                 {
     228          87 :                     nEltSize = sizeof(int64_t);
     229          87 :                     break;
     230             :                 }
     231         150 :                 case OFTReal:
     232             :                 {
     233         150 :                     if (eSubType == OFSTFloat32)
     234             :                     {
     235          64 :                         nEltSize = sizeof(float);
     236             :                     }
     237             :                     else
     238             :                     {
     239          86 :                         nEltSize = sizeof(double);
     240             :                     }
     241         150 :                     break;
     242             :                 }
     243             : 
     244          72 :                 case OFTDateTime:
     245             :                 {
     246          72 :                     if (!bDateTimeAsString)
     247             :                     {
     248          66 :                         if (m_anTZFlags[i] == OGR_TZFLAG_MIXED_TZ)
     249             :                         {
     250           0 :                             psChild->n_buffers = 1;
     251           0 :                             psChild->buffers = static_cast<const void **>(
     252           0 :                                 CPLCalloc(1, sizeof(void *)));
     253             : 
     254           0 :                             psChild->n_children = 2;
     255           0 :                             psChild->children =
     256             :                                 static_cast<struct ArrowArray **>(
     257           0 :                                     CPLCalloc(2, sizeof(struct ArrowArray *)));
     258             : 
     259             :                             // Create sub-child for timestamp in UTC
     260           0 :                             psChild->children[0] =
     261             :                                 static_cast<struct ArrowArray *>(
     262           0 :                                     CPLCalloc(1, sizeof(struct ArrowArray)));
     263           0 :                             psChild->children[0]->release =
     264             :                                 OGRLayer::ReleaseArray;
     265           0 :                             psChild->children[0]->length = m_nMaxBatchSize;
     266           0 :                             psChild->children[0]->n_buffers = 2;
     267           0 :                             psChild->children[0]->buffers =
     268             :                                 static_cast<const void **>(
     269           0 :                                     CPLCalloc(2, sizeof(void *)));
     270           0 :                             psChild->children[0]->buffers[1] =
     271           0 :                                 VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
     272             :                                     sizeof(int64_t) * m_nMaxBatchSize);
     273           0 :                             if (psChild->children[0]->buffers[1] == nullptr)
     274           0 :                                 goto error;
     275           0 :                             memset(const_cast<void *>(
     276           0 :                                        psChild->children[0]->buffers[1]),
     277           0 :                                    0, sizeof(int64_t) * m_nMaxBatchSize);
     278             : 
     279             :                             // Create sub-child for offset to UTC in minutes
     280           0 :                             psChild->children[1] =
     281             :                                 static_cast<struct ArrowArray *>(
     282           0 :                                     CPLCalloc(1, sizeof(struct ArrowArray)));
     283           0 :                             psChild->children[1]->release =
     284             :                                 OGRLayer::ReleaseArray;
     285           0 :                             psChild->children[1]->length = m_nMaxBatchSize;
     286           0 :                             psChild->children[1]->n_buffers = 2;
     287           0 :                             psChild->children[1]->buffers =
     288             :                                 static_cast<const void **>(
     289           0 :                                     CPLCalloc(2, sizeof(void *)));
     290           0 :                             psChild->children[1]->buffers[1] =
     291           0 :                                 VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
     292             :                                     sizeof(int16_t) * m_nMaxBatchSize);
     293           0 :                             if (psChild->children[1]->buffers[1] == nullptr)
     294           0 :                                 goto error;
     295           0 :                             memset(const_cast<void *>(
     296           0 :                                        psChild->children[1]->buffers[1]),
     297           0 :                                    0, sizeof(int16_t) * m_nMaxBatchSize);
     298             :                         }
     299             :                         else
     300             :                         {
     301          66 :                             nEltSize = sizeof(int64_t);
     302             :                         }
     303          66 :                         break;
     304             :                     }
     305             :                     else
     306             :                     {
     307             :                         [[fallthrough]];
     308             :                     }
     309             :                 }
     310             : 
     311             :                 case OFTString:
     312             :                 case OFTBinary:
     313             :                 {
     314         645 :                     psChild->n_buffers = 3;
     315         645 :                     psChild->buffers = static_cast<const void **>(
     316         645 :                         CPLCalloc(3, sizeof(void *)));
     317         645 :                     psChild->buffers[1] = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
     318             :                         sizeof(uint32_t) * (1 + m_nMaxBatchSize));
     319         645 :                     if (psChild->buffers[1] == nullptr)
     320           0 :                         goto error;
     321         645 :                     memset(const_cast<void *>(psChild->buffers[1]), 0,
     322         645 :                            sizeof(uint32_t) * (1 + m_nMaxBatchSize));
     323         645 :                     constexpr size_t DEFAULT_STRING_SIZE = 10;
     324        1290 :                     m_anArrowFieldMaxAlloc[iArrowField] =
     325         645 :                         DEFAULT_STRING_SIZE * m_nMaxBatchSize;
     326         645 :                     psChild->buffers[2] = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
     327             :                         m_anArrowFieldMaxAlloc[iArrowField]);
     328         645 :                     if (psChild->buffers[2] == nullptr)
     329           0 :                         goto error;
     330         645 :                     break;
     331             :                 }
     332             : 
     333          36 :                 case OFTDate:
     334             :                 {
     335          36 :                     nEltSize = sizeof(int32_t);
     336          36 :                     break;
     337             :                 }
     338             : 
     339           0 :                 case OFTTime:
     340             :                 {
     341           0 :                     nEltSize = sizeof(int32_t);
     342           0 :                     break;
     343             :                 }
     344             : 
     345           0 :                 default:
     346           0 :                     break;
     347             :             }
     348             : 
     349        2696 :             if (nEltSize != 0)
     350             :             {
     351        2051 :                 psChild->n_buffers = 2;
     352        2051 :                 psChild->buffers =
     353        2051 :                     static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
     354        4102 :                 psChild->buffers[1] =
     355        2051 :                     VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nEltSize * m_nMaxBatchSize);
     356        2051 :                 if (psChild->buffers[1] == nullptr)
     357           0 :                     goto error;
     358        2051 :                 memset(const_cast<void *>(psChild->buffers[1]), 0,
     359        2051 :                        nEltSize * m_nMaxBatchSize);
     360             :             }
     361             :         }
     362             :     }
     363             : 
     364             :     // cppcheck-suppress knownConditionTrueFalse
     365         839 :     for (int i = 0; i < m_nGeomFieldCount; i++)
     366             :     {
     367         417 :         const int iArrowField = m_mapOGRGeomFieldToArrowField[i];
     368         417 :         if (iArrowField >= 0)
     369             :         {
     370         808 :             out_array->children[iArrowField] = static_cast<struct ArrowArray *>(
     371         404 :                 CPLCalloc(1, sizeof(struct ArrowArray)));
     372         404 :             auto psChild = out_array->children[iArrowField];
     373             : 
     374         404 :             psChild->release = OGRLayer::ReleaseArray;
     375         404 :             psChild->length = m_nMaxBatchSize;
     376             : 
     377         404 :             psChild->n_buffers = 3;
     378         404 :             psChild->buffers =
     379         404 :                 static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
     380         404 :             psChild->buffers[1] = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
     381             :                 sizeof(uint32_t) * (1 + m_nMaxBatchSize));
     382         404 :             if (psChild->buffers[1] == nullptr)
     383           0 :                 goto error;
     384         404 :             memset(const_cast<void *>(psChild->buffers[1]), 0,
     385         404 :                    sizeof(uint32_t) * (1 + m_nMaxBatchSize));
     386         404 :             constexpr size_t DEFAULT_WKB_SIZE = 100;
     387         808 :             m_anArrowFieldMaxAlloc[iArrowField] =
     388         404 :                 DEFAULT_WKB_SIZE * m_nMaxBatchSize;
     389         404 :             psChild->buffers[2] = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
     390             :                 m_anArrowFieldMaxAlloc[iArrowField]);
     391         404 :             if (psChild->buffers[2] == nullptr)
     392           0 :                 goto error;
     393             :         }
     394             :     }
     395             : 
     396         422 :     return;
     397             : 
     398           0 : error:
     399           0 :     out_array->release(out_array);
     400           0 :     memset(out_array, 0, sizeof(*out_array));
     401             : }
     402             : 
     403             : /************************************************************************/
     404             : /*                             FillDict()                               */
     405             : /************************************************************************/
     406             : 
     407             : /* static */
     408          37 : bool OGRArrowArrayHelper::FillDict(struct ArrowArray *psChild,
     409             :                                    const OGRCodedFieldDomain *poCodedDomain)
     410             : {
     411          37 :     int nLastCode = -1;
     412          37 :     uint32_t nCountChars = 0;
     413          37 :     int nCountNull = 0;
     414          37 :     for (const OGRCodedValue *psIter = poCodedDomain->GetEnumeration();
     415         121 :          psIter->pszCode; ++psIter)
     416             :     {
     417          84 :         if (CPLGetValueType(psIter->pszCode) != CPL_VALUE_INTEGER)
     418             :         {
     419           0 :             return false;
     420             :         }
     421          84 :         int nCode = atoi(psIter->pszCode);
     422          84 :         if (nCode <= nLastCode || nCode - nLastCode > 100)
     423             :         {
     424           0 :             return false;
     425             :         }
     426         115 :         for (int i = nLastCode + 1; i < nCode; ++i)
     427             :         {
     428          31 :             nCountNull++;
     429             :         }
     430          84 :         if (psIter->pszValue)
     431             :         {
     432          53 :             const size_t nLen = strlen(psIter->pszValue);
     433          53 :             if (nLen > std::numeric_limits<uint32_t>::max() - nCountChars)
     434           0 :                 return false;
     435          53 :             nCountChars += static_cast<uint32_t>(nLen);
     436             :         }
     437             :         else
     438             :         {
     439          31 :             nCountNull++;
     440             :         }
     441          84 :         nLastCode = nCode;
     442             :     }
     443          37 :     const int nLength = 1 + nLastCode;
     444             : 
     445             :     auto psDict = static_cast<struct ArrowArray *>(
     446          37 :         CPLCalloc(1, sizeof(struct ArrowArray)));
     447          37 :     psChild->dictionary = psDict;
     448             : 
     449          37 :     psDict->release = OGRLayer::ReleaseArray;
     450          37 :     psDict->length = nLength;
     451          37 :     psDict->n_buffers = 3;
     452          37 :     psDict->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
     453          37 :     psDict->null_count = nCountNull;
     454          37 :     uint8_t *pabyNull = nullptr;
     455          37 :     if (nCountNull)
     456             :     {
     457             :         pabyNull = static_cast<uint8_t *>(
     458          31 :             VSI_MALLOC_ALIGNED_AUTO_VERBOSE((nLength + 7) / 8));
     459          31 :         if (pabyNull == nullptr)
     460             :         {
     461           0 :             psDict->release(psDict);
     462           0 :             CPLFree(psDict);
     463           0 :             psChild->dictionary = nullptr;
     464           0 :             return false;
     465             :         }
     466          31 :         memset(pabyNull, 0xFF, (nLength + 7) / 8);
     467          31 :         psDict->buffers[0] = pabyNull;
     468             :     }
     469             : 
     470             :     uint32_t *panOffsets = static_cast<uint32_t *>(
     471          37 :         VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(uint32_t) * (1 + nLength)));
     472          37 :     if (panOffsets == nullptr)
     473             :     {
     474           0 :         psDict->release(psDict);
     475           0 :         CPLFree(psDict);
     476           0 :         psChild->dictionary = nullptr;
     477           0 :         return false;
     478             :     }
     479          37 :     psDict->buffers[1] = panOffsets;
     480             : 
     481             :     char *pachValues =
     482          37 :         static_cast<char *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nCountChars));
     483          37 :     if (pachValues == nullptr)
     484             :     {
     485           0 :         psDict->release(psDict);
     486           0 :         CPLFree(psDict);
     487           0 :         psChild->dictionary = nullptr;
     488           0 :         return false;
     489             :     }
     490          37 :     psDict->buffers[2] = pachValues;
     491             : 
     492          37 :     nLastCode = -1;
     493          37 :     uint32_t nOffset = 0;
     494          37 :     for (const OGRCodedValue *psIter = poCodedDomain->GetEnumeration();
     495         121 :          psIter->pszCode; ++psIter)
     496             :     {
     497          84 :         if (CPLGetValueType(psIter->pszCode) != CPL_VALUE_INTEGER)
     498             :         {
     499           0 :             psDict->release(psDict);
     500           0 :             CPLFree(psDict);
     501           0 :             psChild->dictionary = nullptr;
     502           0 :             return false;
     503             :         }
     504          84 :         int nCode = atoi(psIter->pszCode);
     505          84 :         if (nCode <= nLastCode || nCode - nLastCode > 100)
     506             :         {
     507           0 :             psDict->release(psDict);
     508           0 :             CPLFree(psDict);
     509           0 :             psChild->dictionary = nullptr;
     510           0 :             return false;
     511             :         }
     512         115 :         for (int i = nLastCode + 1; i < nCode; ++i)
     513             :         {
     514          31 :             panOffsets[i] = nOffset;
     515          31 :             if (pabyNull)
     516          31 :                 pabyNull[i / 8] &= static_cast<uint8_t>(
     517          31 :                     ~(1 << (static_cast<unsigned>(i) % 8)));
     518             :         }
     519          84 :         panOffsets[nCode] = nOffset;
     520          84 :         if (psIter->pszValue)
     521             :         {
     522          53 :             const size_t nLen = strlen(psIter->pszValue);
     523          53 :             memcpy(pachValues + nOffset, psIter->pszValue, nLen);
     524          53 :             nOffset += static_cast<uint32_t>(nLen);
     525             :         }
     526          31 :         else if (pabyNull)
     527             :         {
     528          31 :             pabyNull[nCode / 8] &= static_cast<uint8_t>(~(1 << (nCode % 8)));
     529             :         }
     530          84 :         nLastCode = nCode;
     531             :     }
     532          37 :     panOffsets[nLength] = nOffset;
     533             : 
     534          37 :     return true;
     535             : }
     536             : 
     537             : //! @endcond

Generated by: LCOV version 1.14