LCOV - code coverage report
Current view: top level - gcore - nasakeywordhandler.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 247 261 94.6 %
Date: 2025-09-10 17:48:50 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  PDS Driver; Planetary Data System Format
       4             :  * Purpose:  Implementation of NASAKeywordHandler - a class to read
       5             :  *           keyword data from PDS, ISIS2 and ISIS3 data products.
       6             :  * Author:   Frank Warmerdam <warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2006, Frank Warmerdam <warmerdam@pobox.com>
      10             :  * Copyright (c) 2008-2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  * Copyright (c) 2017 Hobu Inc
      12             :  * Copyright (c) 2017, Dmitry Baryshnikov <polimax@mail.ru>
      13             :  * Copyright (c) 2017, NextGIS <info@nextgis.com>
      14             :  *
      15             :  * SPDX-License-Identifier: MIT
      16             :  ****************************************************************************
      17             :  * Object Description Language (ODL) is used to encode data labels for PDS
      18             :  * and other NASA data systems. Refer to Chapter 12 of "PDS Standards
      19             :  * Reference" at http://pds.jpl.nasa.gov/tools/standards-reference.shtml for
      20             :  * further details about ODL.
      21             :  *
      22             :  * This is also known as PVL (Parameter Value Language) which is written
      23             :  * about at http://www.orrery.us/node/44 where it notes:
      24             :  *
      25             :  * The PVL syntax that the PDS uses is specified by the Consultative Committee
      26             :  * for Space Data Systems in their Blue Book publication: "Parameter Value
      27             :  * Language Specification (CCSD0006 and CCSD0008)", June 2000
      28             :  * [CCSDS 641.0-B-2], and Green Book publication: "Parameter Value Language -
      29             :  * A Tutorial", June 2000 [CCSDS 641.0-G-2]. PVL has also been accepted by the
      30             :  * International Standards Organization (ISO), as a Final Draft International
      31             :  * Standard (ISO 14961:2002) keyword value type language for naming and
      32             :  * expressing data values.
      33             :  * --
      34             :  * also of interest, on PDS ODL:
      35             :  *  http://pds.jpl.nasa.gov/documents/sr/Chapter12.pdf
      36             :  *
      37             :  ****************************************************************************/
      38             : 
      39             : #include "nasakeywordhandler.h"
      40             : #include "ogrlibjsonutils.h"
      41             : #include <vector>
      42             : 
      43             : //! @cond Doxygen_Suppress
      44             : 
      45             : /************************************************************************/
      46             : /* ==================================================================== */
      47             : /*                          NASAKeywordHandler                          */
      48             : /* ==================================================================== */
      49             : /************************************************************************/
      50             : 
      51             : /************************************************************************/
      52             : /*                         NASAKeywordHandler()                         */
      53             : /************************************************************************/
      54             : 
      55         467 : NASAKeywordHandler::NASAKeywordHandler()
      56         467 :     : pszHeaderNext(nullptr), m_bStripSurroundingQuotes(false)
      57             : {
      58         467 :     oJSon.Deinit();
      59         467 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                        ~NASAKeywordHandler()                         */
      63             : /************************************************************************/
      64             : 
      65         467 : NASAKeywordHandler::~NASAKeywordHandler()
      66             : 
      67             : {
      68         467 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                               Ingest()                               */
      72             : /************************************************************************/
      73             : 
      74         308 : bool NASAKeywordHandler::Ingest(VSILFILE *fp, int nOffset)
      75             : 
      76             : {
      77             :     /* -------------------------------------------------------------------- */
      78             :     /*      Read in buffer till we find END all on its own line.            */
      79             :     /* -------------------------------------------------------------------- */
      80         308 :     if (VSIFSeekL(fp, nOffset, SEEK_SET) != 0)
      81           0 :         return false;
      82             : 
      83         616 :     std::string osHeaderText;
      84             :     for (; true;)
      85             :     {
      86             :         char szChunk[513];
      87             : 
      88        3648 :         int nBytesRead = static_cast<int>(VSIFReadL(szChunk, 1, 512, fp));
      89             : 
      90        3648 :         szChunk[nBytesRead] = '\0';
      91        3648 :         osHeaderText += szChunk;
      92             : 
      93        3648 :         if (nBytesRead < 512)
      94         161 :             break;
      95             : 
      96        3487 :         const char *pszCheck = nullptr;
      97        3487 :         if (osHeaderText.size() > 520)
      98         499 :             pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
      99             :         else
     100        2988 :             pszCheck = szChunk;
     101             : 
     102        3487 :         if (strstr(pszCheck, "\r\nEND\r\n") != nullptr ||
     103        3472 :             strstr(pszCheck, "\nEND\n") != nullptr ||
     104        3463 :             strstr(pszCheck, "\r\nEnd\r\n") != nullptr ||
     105        3463 :             strstr(pszCheck, "\nEnd\n") != nullptr)
     106             :             break;
     107        3340 :     }
     108             : 
     109         308 :     return Parse(osHeaderText.c_str());
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                               Parse()                                */
     114             : /************************************************************************/
     115             : 
     116         338 : bool NASAKeywordHandler::Parse(const char *pszStr)
     117             : 
     118             : {
     119         338 :     pszHeaderNext = pszStr;
     120             : 
     121             :     /* -------------------------------------------------------------------- */
     122             :     /*      Process name/value pairs, keeping track of a "path stack".      */
     123             :     /* -------------------------------------------------------------------- */
     124         338 :     oJSon = CPLJSONObject();
     125         338 :     return ReadGroup("", oJSon, 0);
     126             : }
     127             : 
     128             : /************************************************************************/
     129             : /*                             ReadGroup()                              */
     130             : /************************************************************************/
     131             : 
     132        2743 : bool NASAKeywordHandler::ReadGroup(const std::string &osPathPrefix,
     133             :                                    CPLJSONObject &oCur, int nRecLevel)
     134             : 
     135             : {
     136        2743 :     if (osPathPrefix.size() > 256)
     137             :     {
     138           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too big prefix for GROUP");
     139           0 :         return false;
     140             :     }
     141        2743 :     if (nRecLevel == 100)
     142           0 :         return false;
     143             :     for (; true;)
     144             :     {
     145       14532 :         CPLString osName, osValue;
     146       14532 :         if (!ReadPair(osName, osValue, oCur))
     147           3 :             return false;
     148             : 
     149       14529 :         if (EQUAL(osName, "OBJECT") || EQUAL(osName, "GROUP"))
     150             :         {
     151        2405 :             CPLJSONObject oNewGroup;
     152        2405 :             oNewGroup.Add("_type",
     153        2405 :                           EQUAL(osName, "OBJECT") ? "object" : "group");
     154        2405 :             if (!ReadGroup((osPathPrefix + osValue + ".").c_str(), oNewGroup,
     155             :                            nRecLevel + 1))
     156             :             {
     157           0 :                 return false;
     158             :             }
     159        7215 :             CPLJSONObject oName = oNewGroup["Name"];
     160        2405 :             if (oName.GetType() == CPLJSONObject::Type::String)
     161             :             {
     162         285 :                 oCur.Add(osValue + "_" + oName.ToString(), oNewGroup);
     163         285 :                 oNewGroup.Add("_container_name", osValue);
     164             :             }
     165        2120 :             else if (oCur[osValue].IsValid())
     166             :             {
     167           4 :                 int nIter = 2;
     168           6 :                 while (oCur[osValue + CPLSPrintf("_%d", nIter)].IsValid())
     169             :                 {
     170           2 :                     nIter++;
     171             :                 }
     172           4 :                 oCur.Add(osValue + CPLSPrintf("_%d", nIter), oNewGroup);
     173           4 :                 oNewGroup.Add("_container_name", osValue);
     174             :             }
     175             :             else
     176             :             {
     177        2116 :                 oCur.Add(osValue, oNewGroup);
     178             :             }
     179             :         }
     180       22900 :         else if (EQUAL(osName, "END") || EQUAL(osName, "END_GROUP") ||
     181       10776 :                  EQUAL(osName, "END_OBJECT"))
     182             :         {
     183        2740 :             return true;
     184             :         }
     185             :         else
     186             :         {
     187        9384 :             osName = osPathPrefix + osName;
     188        9384 :             aosKeywordList.AddNameValue(osName, osValue);
     189             :         }
     190       11789 :     }
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                        StripQuotesIfNeeded()                         */
     195             : /************************************************************************/
     196             : 
     197        5124 : static CPLString StripQuotesIfNeeded(const CPLString &osWord,
     198             :                                      bool bQuotesAlreadyRemoved)
     199             : {
     200        5124 :     if (bQuotesAlreadyRemoved || osWord.size() < 2 || osWord[0] != '"')
     201        3347 :         return osWord;
     202        3554 :     return osWord.substr(1, osWord.size() - 2);
     203             : }
     204             : 
     205             : /************************************************************************/
     206             : /*                              ReadPair()                              */
     207             : /*                                                                      */
     208             : /*      Read a name/value pair from the input stream.  Strip off        */
     209             : /*      white space, ignore comments, split on '='.                     */
     210             : /*      Returns TRUE on success.                                        */
     211             : /************************************************************************/
     212             : 
     213       14532 : bool NASAKeywordHandler::ReadPair(CPLString &osName, CPLString &osValue,
     214             :                                   CPLJSONObject &oCur)
     215             : 
     216             : {
     217       14532 :     osName = "";
     218       14532 :     osValue = "";
     219             : 
     220       14532 :     if (!ReadWord(osName))
     221           0 :         return false;
     222             : 
     223       14532 :     SkipWhite();
     224             : 
     225       14532 :     if (EQUAL(osName, "END"))
     226         335 :         return true;
     227             : 
     228       14197 :     if (*pszHeaderNext != '=')
     229             :     {
     230             :         // ISIS3 does not have anything after the end group/object keyword.
     231        1772 :         if (EQUAL(osName, "End_Group") || EQUAL(osName, "End_Object"))
     232        1771 :             return true;
     233             : 
     234           1 :         return false;
     235             :     }
     236             : 
     237       12425 :     pszHeaderNext++;
     238             : 
     239       12425 :     SkipWhite();
     240             : 
     241       12425 :     osValue = "";
     242       12425 :     bool bIsString = true;
     243             : 
     244             :     // Handle value lists like:
     245             :     // Name   = (Red, Red) or  {Red, Red} or even ({Red, Red}, {Red, Red})
     246       24850 :     CPLJSONArray oArray;
     247       12425 :     if (*pszHeaderNext == '(' || *pszHeaderNext == '{')
     248             :     {
     249         424 :         std::vector<char> oStackArrayBeginChar;
     250         424 :         CPLString osWord;
     251             : 
     252         424 :         oStackArrayBeginChar.push_back(*pszHeaderNext);
     253         424 :         osValue += *pszHeaderNext;
     254         424 :         pszHeaderNext++;
     255             : 
     256        1303 :         while (ReadWord(osWord, m_bStripSurroundingQuotes, true, &bIsString))
     257             :         {
     258        1303 :             if (*pszHeaderNext == '(' || *pszHeaderNext == '{')
     259             :             {
     260           3 :                 oStackArrayBeginChar.push_back(*pszHeaderNext);
     261           3 :                 osValue += *pszHeaderNext;
     262           3 :                 pszHeaderNext++;
     263             :             }
     264             : 
     265             :             // TODO: we could probably do better with nested json arrays
     266             :             // instead of flattening when there are (( )) or ({ }) constructs
     267        1303 :             if (bIsString)
     268             :             {
     269         947 :                 if (!(osWord.empty() &&
     270           8 :                       (*pszHeaderNext == '(' || *pszHeaderNext == '{' ||
     271           8 :                        *pszHeaderNext == ')' || *pszHeaderNext == '}')))
     272             :                 {
     273         935 :                     oArray.Add(
     274        1870 :                         StripQuotesIfNeeded(osWord, m_bStripSurroundingQuotes));
     275             :                 }
     276             :             }
     277         364 :             else if (CPLGetValueType(osWord) == CPL_VALUE_INTEGER)
     278             :             {
     279         229 :                 oArray.Add(atoi(osWord));
     280             :             }
     281             :             else
     282             :             {
     283         135 :                 oArray.Add(CPLAtof(osWord));
     284             :             }
     285             : 
     286        1303 :             osValue += osWord;
     287        1316 :             while (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     288             :             {
     289          13 :                 pszHeaderNext++;
     290             :             }
     291             : 
     292        1303 :             if (*pszHeaderNext == ')')
     293             :             {
     294         414 :                 osValue += *pszHeaderNext;
     295         828 :                 if (oStackArrayBeginChar.empty() ||
     296         414 :                     oStackArrayBeginChar.back() != '(')
     297             :                 {
     298           1 :                     CPLDebug("PDS", "Unpaired ( ) for %s", osName.c_str());
     299           1 :                     return false;
     300             :                 }
     301         413 :                 oStackArrayBeginChar.pop_back();
     302         413 :                 pszHeaderNext++;
     303         413 :                 if (oStackArrayBeginChar.empty())
     304         412 :                     break;
     305             :             }
     306         889 :             else if (*pszHeaderNext == '}')
     307             :             {
     308          13 :                 osValue += *pszHeaderNext;
     309          26 :                 if (oStackArrayBeginChar.empty() ||
     310          13 :                     oStackArrayBeginChar.back() != '{')
     311             :                 {
     312           1 :                     CPLDebug("PDS", "Unpaired { } for %s", osName.c_str());
     313           1 :                     return false;
     314             :                 }
     315          12 :                 oStackArrayBeginChar.pop_back();
     316          12 :                 pszHeaderNext++;
     317          12 :                 if (oStackArrayBeginChar.empty())
     318          10 :                     break;
     319             :             }
     320         876 :             else if (*pszHeaderNext == ',')
     321             :             {
     322         873 :                 osValue += *pszHeaderNext;
     323         873 :                 pszHeaderNext++;
     324             :                 // Do not use SkipWhite() here to avoid being confuse by
     325             :                 // constructs like
     326             :                 // FOO = (#123456,
     327             :                 //        #123456)
     328             :                 // where we could confuse the second line with a comment.
     329        3220 :                 while (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     330             :                 {
     331        2347 :                     pszHeaderNext++;
     332             :                 }
     333             :             }
     334         879 :             SkipWhite();
     335         422 :         }
     336             :     }
     337             : 
     338             :     else  // Handle more normal "single word" values.
     339             :     {
     340       12001 :         if (!ReadWord(osValue, m_bStripSurroundingQuotes, false, &bIsString))
     341           0 :             return false;
     342             :     }
     343             : 
     344       12423 :     SkipWhite();
     345             : 
     346             :     // No units keyword?
     347       12423 :     if (*pszHeaderNext != '<')
     348             :     {
     349       11677 :         if (!EQUAL(osName, "OBJECT") && !EQUAL(osName, "GROUP"))
     350             :         {
     351        9272 :             if (oArray.Size() > 0)
     352             :             {
     353         418 :                 oCur.Add(osName, oArray);
     354             :             }
     355             :             else
     356             :             {
     357        8854 :                 if (bIsString)
     358             :                 {
     359        4189 :                     oCur.Add(osName, StripQuotesIfNeeded(
     360        4189 :                                          osValue, m_bStripSurroundingQuotes));
     361             :                 }
     362        4665 :                 else if (CPLGetValueType(osValue) == CPL_VALUE_INTEGER)
     363             :                 {
     364        2902 :                     oCur.Add(osName, atoi(osValue));
     365             :                 }
     366             :                 else
     367             :                 {
     368        1763 :                     oCur.Add(osName, CPLAtof(osValue));
     369             :                 }
     370             :             }
     371             :         }
     372       11677 :         return true;
     373             :     }
     374             : 
     375        1492 :     CPLString osValueNoUnit(osValue);
     376             :     // Append units keyword.  For lines that like like this:
     377             :     //  MAP_RESOLUTION               = 4.0 <PIXEL/DEGREE>
     378             : 
     379         746 :     osValue += " ";
     380             : 
     381        1492 :     CPLString osWord;
     382        1492 :     CPLString osUnit;
     383         746 :     while (ReadWord(osWord))
     384             :     {
     385         746 :         SkipWhite();
     386             : 
     387         746 :         osValue += osWord;
     388         746 :         osUnit = osWord;
     389         746 :         if (osWord.back() == '>')
     390         746 :             break;
     391             :     }
     392             : 
     393         746 :     if (osUnit[0] == '<')
     394         746 :         osUnit = osUnit.substr(1);
     395         746 :     if (!osUnit.empty() && osUnit.back() == '>')
     396         746 :         osUnit = osUnit.substr(0, osUnit.size() - 1);
     397             : 
     398         746 :     CPLJSONObject newObject;
     399         746 :     oCur.Add(osName, newObject);
     400             : 
     401         746 :     if (oArray.Size() > 0)
     402             :     {
     403           2 :         newObject.Add("value", oArray);
     404             :     }
     405             :     else
     406             :     {
     407         744 :         if (bIsString)
     408             :         {
     409          10 :             newObject.Add("value", osValueNoUnit);
     410             :         }
     411         734 :         else if (CPLGetValueType(osValueNoUnit) == CPL_VALUE_INTEGER)
     412             :         {
     413          38 :             newObject.Add("value", atoi(osValueNoUnit));
     414             :         }
     415             :         else
     416             :         {
     417         696 :             newObject.Add("value", CPLAtof(osValueNoUnit));
     418             :         }
     419             :     }
     420         746 :     newObject.Add("unit", osUnit);
     421             : 
     422         746 :     return true;
     423             : }
     424             : 
     425             : /************************************************************************/
     426             : /*                              ReadWord()                              */
     427             : /*  Returns TRUE on success                                             */
     428             : /************************************************************************/
     429             : 
     430       28582 : bool NASAKeywordHandler::ReadWord(CPLString &osWord,
     431             :                                   bool bStripSurroundingQuotes, bool bParseList,
     432             :                                   bool *pbIsString)
     433             : 
     434             : {
     435       28582 :     if (pbIsString)
     436       13304 :         *pbIsString = false;
     437       28582 :     osWord = "";
     438             : 
     439       28582 :     SkipWhite();
     440             : 
     441       28582 :     if (!(*pszHeaderNext != '\0' && *pszHeaderNext != '=' &&
     442       28582 :           !isspace(static_cast<unsigned char>(*pszHeaderNext))))
     443           0 :         return false;
     444             : 
     445             :     /* Extract a text string delimited by '\"' */
     446             :     /* Convert newlines (CR or LF) within quotes. While text strings
     447             :        support them as per ODL, the keyword list doesn't want them */
     448       28582 :     if (*pszHeaderNext == '"')
     449             :     {
     450        1813 :         if (pbIsString)
     451        1813 :             *pbIsString = true;
     452        1813 :         if (!bStripSurroundingQuotes)
     453        1779 :             osWord += *(pszHeaderNext);
     454        1813 :         pszHeaderNext++;
     455       27179 :         while (*pszHeaderNext != '"')
     456             :         {
     457       25366 :             if (*pszHeaderNext == '\0')
     458           0 :                 return false;
     459       25366 :             if (*pszHeaderNext == '\n')
     460             :             {
     461         121 :                 osWord += "\\n";
     462         121 :                 pszHeaderNext++;
     463         121 :                 continue;
     464             :             }
     465       25245 :             if (*pszHeaderNext == '\r')
     466             :             {
     467         118 :                 osWord += "\\r";
     468         118 :                 pszHeaderNext++;
     469         118 :                 continue;
     470             :             }
     471       25127 :             osWord += *(pszHeaderNext++);
     472             :         }
     473        1813 :         if (!bStripSurroundingQuotes)
     474        1779 :             osWord += *(pszHeaderNext);
     475        1813 :         pszHeaderNext++;
     476             : 
     477        1813 :         return true;
     478             :     }
     479             : 
     480             :     /* Extract a symbol string */
     481             :     /* These are expected to not have
     482             :        '\'' (delimiters),
     483             :        format effectors (should fit on a single line) or
     484             :        control characters.
     485             :     */
     486       26769 :     if (*pszHeaderNext == '\'')
     487             :     {
     488           8 :         if (pbIsString)
     489           8 :             *pbIsString = true;
     490           8 :         if (!bStripSurroundingQuotes)
     491           8 :             osWord += *(pszHeaderNext);
     492           8 :         pszHeaderNext++;
     493          32 :         while (*pszHeaderNext != '\'')
     494             :         {
     495          24 :             if (*pszHeaderNext == '\0')
     496           0 :                 return false;
     497             : 
     498          24 :             osWord += *(pszHeaderNext++);
     499             :         }
     500           8 :         if (!bStripSurroundingQuotes)
     501           8 :             osWord += *(pszHeaderNext);
     502           8 :         pszHeaderNext++;
     503           8 :         return true;
     504             :     }
     505             : 
     506             :     /*
     507             :      * Extract normal text.  Terminated by '=' or whitespace.
     508             :      *
     509             :      * A special exception is that a line may terminate with a '-'
     510             :      * which is taken as a line extender, and we suck up white space to new
     511             :      * text.
     512             :      */
     513      239048 :     while (
     514      265809 :         *pszHeaderNext != '\0' && *pszHeaderNext != '=' &&
     515      263861 :         ((bParseList && *pszHeaderNext != ',' && *pszHeaderNext != '(' &&
     516        5331 :           *pszHeaderNext != ')' && *pszHeaderNext != '{' &&
     517      263861 :           *pszHeaderNext != '}') ||
     518      258044 :          (!bParseList && !isspace(static_cast<unsigned char>(*pszHeaderNext)))))
     519             :     {
     520      239048 :         osWord += *pszHeaderNext;
     521      239048 :         pszHeaderNext++;
     522             : 
     523      239048 :         if (*pszHeaderNext == '-' &&
     524         145 :             (pszHeaderNext[1] == 10 || pszHeaderNext[1] == 13))
     525             :         {
     526           4 :             pszHeaderNext += 2;
     527           4 :             SkipWhite();
     528             :         }
     529             :     }
     530             : 
     531       26761 :     if (pbIsString)
     532       11483 :         *pbIsString = CPLGetValueType(osWord) == CPL_VALUE_STRING;
     533             : 
     534       26761 :     return true;
     535             : }
     536             : 
     537             : /************************************************************************/
     538             : /*                             SkipWhite()                              */
     539             : /*  Skip white spaces and C style comments                              */
     540             : /************************************************************************/
     541             : 
     542      224874 : void NASAKeywordHandler::SkipWhite()
     543             : 
     544             : {
     545             :     for (; true;)
     546             :     {
     547             :         // Skip C style comments
     548      224874 :         if (*pszHeaderNext == '/' && pszHeaderNext[1] == '*')
     549             :         {
     550         333 :             pszHeaderNext += 2;
     551             : 
     552       17886 :             while (*pszHeaderNext != '\0' &&
     553       17886 :                    (*pszHeaderNext != '*' || pszHeaderNext[1] != '/'))
     554             :             {
     555       17553 :                 pszHeaderNext++;
     556             :             }
     557         333 :             if (*pszHeaderNext == '\0')
     558           0 :                 return;
     559             : 
     560         333 :             pszHeaderNext += 2;
     561             : 
     562             :             // consume till end of line.
     563             :             // reduce sensibility to a label error
     564         333 :             while (*pszHeaderNext != '\0' && *pszHeaderNext != 10 &&
     565         294 :                    *pszHeaderNext != 13)
     566             :             {
     567           0 :                 pszHeaderNext++;
     568             :             }
     569         333 :             continue;
     570             :         }
     571             : 
     572             :         // Skip # style comments
     573      224541 :         if ((*pszHeaderNext == 10 || *pszHeaderNext == 13 ||
     574      205224 :              *pszHeaderNext == ' ' || *pszHeaderNext == '\t') &&
     575      154950 :             pszHeaderNext[1] == '#')
     576             :         {
     577          83 :             pszHeaderNext += 2;
     578             : 
     579             :             // consume till end of line.
     580        4138 :             while (*pszHeaderNext != '\0' && *pszHeaderNext != 10 &&
     581        4055 :                    *pszHeaderNext != 13)
     582             :             {
     583        4055 :                 pszHeaderNext++;
     584             :             }
     585          83 :             continue;
     586             :         }
     587             : 
     588             :         // Skip white space (newline, space, tab, etc )
     589      224458 :         if (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     590             :         {
     591      154867 :             pszHeaderNext++;
     592      154867 :             continue;
     593             :         }
     594             : 
     595             :         // not white space, return.
     596       69591 :         return;
     597             :     }
     598             : }
     599             : 
     600             : /************************************************************************/
     601             : /*                             GetKeyword()                             */
     602             : /************************************************************************/
     603             : 
     604        8167 : const char *NASAKeywordHandler::GetKeyword(const char *pszPath,
     605             :                                            const char *pszDefault)
     606             : 
     607             : {
     608        8167 :     return aosKeywordList.FetchNameValueDef(pszPath, pszDefault);
     609             : }
     610             : 
     611             : /************************************************************************/
     612             : /*                             GetKeywordList()                         */
     613             : /************************************************************************/
     614             : 
     615           0 : char **NASAKeywordHandler::GetKeywordList()
     616             : {
     617           0 :     return aosKeywordList.List();
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                               StealJSon()                            */
     622             : /************************************************************************/
     623             : 
     624         326 : CPLJSONObject NASAKeywordHandler::GetJsonObject() const
     625             : {
     626         326 :     return oJSon;
     627             : }
     628             : 
     629             : //! @endcond

Generated by: LCOV version 1.14