LCOV - code coverage report
Current view: top level - gcore - nasakeywordhandler.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 280 296 94.6 %
Date: 2026-05-13 23:47:50 Functions: 12 13 92.3 %

          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         477 : NASAKeywordHandler::NASAKeywordHandler()
      56         477 :     : pszHeaderNext(nullptr), m_bStripSurroundingQuotes(false)
      57             : {
      58         477 :     oJSon.Deinit();
      59         477 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                        ~NASAKeywordHandler()                         */
      63             : /************************************************************************/
      64             : 
      65         477 : NASAKeywordHandler::~NASAKeywordHandler()
      66             : 
      67             : {
      68         477 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                               Ingest()                               */
      72             : /************************************************************************/
      73             : 
      74         314 : bool NASAKeywordHandler::Ingest(VSILFILE *fp, vsi_l_offset nOffset)
      75             : 
      76             : {
      77             :     /* -------------------------------------------------------------------- */
      78             :     /*      Read in buffer till we find END all on its own line.            */
      79             :     /* -------------------------------------------------------------------- */
      80         314 :     if (VSIFSeekL(fp, nOffset, SEEK_SET) != 0)
      81           0 :         return false;
      82             : 
      83         628 :     std::string osHeaderText;
      84             :     for (; true;)
      85             :     {
      86             :         char szChunk[513];
      87             : 
      88        3658 :         int nBytesRead = static_cast<int>(VSIFReadL(szChunk, 1, 512, fp));
      89             : 
      90        3658 :         szChunk[nBytesRead] = '\0';
      91        3658 :         osHeaderText += szChunk;
      92             : 
      93        3658 :         if (nBytesRead < 512)
      94         167 :             break;
      95             : 
      96        3491 :         const char *pszCheck = nullptr;
      97        3491 :         if (osHeaderText.size() > 520)
      98         500 :             pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
      99             :         else
     100        2991 :             pszCheck = szChunk;
     101             : 
     102        3491 :         if (strstr(pszCheck, "\r\nEND\r\n") != nullptr ||
     103        3476 :             strstr(pszCheck, "\nEND\n") != nullptr ||
     104        3467 :             strstr(pszCheck, "\r\nEnd\r\n") != nullptr ||
     105        3467 :             strstr(pszCheck, "\nEnd\n") != nullptr)
     106             :             break;
     107        3344 :     }
     108             : 
     109         314 :     return Parse(osHeaderText.c_str());
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                               Parse()                                */
     114             : /************************************************************************/
     115             : 
     116         346 : bool NASAKeywordHandler::Parse(const char *pszStr)
     117             : 
     118             : {
     119         346 :     pszHeaderNext = pszStr;
     120             : 
     121             :     /* -------------------------------------------------------------------- */
     122             :     /*      Process name/value pairs, keeping track of a "path stack".      */
     123             :     /* -------------------------------------------------------------------- */
     124         346 :     oJSon = CPLJSONObject();
     125         346 :     return ReadGroup("", oJSon, 0);
     126             : }
     127             : 
     128             : /************************************************************************/
     129             : /*                             ReadGroup()                              */
     130             : /************************************************************************/
     131             : 
     132        2830 : bool NASAKeywordHandler::ReadGroup(const std::string &osPathPrefix,
     133             :                                    CPLJSONObject &oCur, int nRecLevel)
     134             : 
     135             : {
     136        2830 :     if (osPathPrefix.size() > 256)
     137             :     {
     138           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too big prefix for GROUP");
     139           0 :         return false;
     140             :     }
     141        2830 :     if (nRecLevel == 100)
     142           0 :         return false;
     143             :     for (; true;)
     144             :     {
     145       14935 :         CPLString osName, osValue;
     146       14935 :         if (!ReadPair(osName, osValue, oCur))
     147           3 :             return false;
     148             : 
     149       14932 :         if (EQUAL(osName, "OBJECT") || EQUAL(osName, "GROUP"))
     150             :         {
     151        2484 :             CPLJSONObject oNewGroup;
     152        2484 :             oNewGroup.Add("_type",
     153        2484 :                           EQUAL(osName, "OBJECT") ? "object" : "group");
     154        2484 :             if (!ReadGroup((osPathPrefix + osValue + ".").c_str(), oNewGroup,
     155             :                            nRecLevel + 1))
     156             :             {
     157           0 :                 return false;
     158             :             }
     159        7452 :             CPLJSONObject oName = oNewGroup["Name"];
     160        2484 :             if (oName.GetType() == CPLJSONObject::Type::String)
     161             :             {
     162         285 :                 oCur.AddNoSplitName(osValue + "_" + oName.ToString(),
     163             :                                     oNewGroup);
     164         285 :                 oNewGroup.Add("_container_name", osValue);
     165             :             }
     166        2199 :             else if (oCur[osValue].IsValid())
     167             :             {
     168           4 :                 int nIter = 2;
     169           6 :                 while (oCur[osValue + CPLSPrintf("_%d", nIter)].IsValid())
     170             :                 {
     171           2 :                     nIter++;
     172             :                 }
     173           4 :                 oCur.AddNoSplitName(osValue + CPLSPrintf("_%d", nIter),
     174             :                                     oNewGroup);
     175           4 :                 oNewGroup.Add("_container_name", osValue);
     176             :             }
     177             :             else
     178             :             {
     179        2195 :                 oCur.AddNoSplitName(osValue, oNewGroup);
     180             :             }
     181             :         }
     182       23503 :         else if (EQUAL(osName, "END") || EQUAL(osName, "END_GROUP") ||
     183       11055 :                  EQUAL(osName, "END_OBJECT"))
     184             :         {
     185        2827 :             return true;
     186             :         }
     187             :         else
     188             :         {
     189        9621 :             osName = osPathPrefix + osName;
     190        9621 :             aosKeywordList.AddNameValue(osName, osValue);
     191             :         }
     192       12105 :     }
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                        StripQuotesIfNeeded()                         */
     197             : /************************************************************************/
     198             : 
     199        5373 : static CPLString StripQuotesIfNeeded(const CPLString &osWord,
     200             :                                      bool bQuotesAlreadyRemoved)
     201             : {
     202        5373 :     if (bQuotesAlreadyRemoved || osWord.size() < 2 || osWord[0] != '"')
     203        3447 :         return osWord;
     204        3852 :     return osWord.substr(1, osWord.size() - 2);
     205             : }
     206             : 
     207             : /************************************************************************/
     208             : /*                              ReadPair()                              */
     209             : /*                                                                      */
     210             : /*      Read a name/value pair from the input stream.  Strip off        */
     211             : /*      white space, ignore comments, split on '='.                     */
     212             : /*      Returns TRUE on success.                                        */
     213             : /************************************************************************/
     214             : 
     215       14935 : bool NASAKeywordHandler::ReadPair(CPLString &osName, CPLString &osValue,
     216             :                                   CPLJSONObject &oCur)
     217             : 
     218             : {
     219       14935 :     osName = "";
     220       14935 :     osValue = "";
     221             : 
     222       14935 :     if (!ReadWord(osName))
     223           0 :         return false;
     224             : 
     225       14935 :     SkipWhite();
     226             : 
     227       14935 :     if (EQUAL(osName, "END"))
     228         343 :         return true;
     229             : 
     230       14592 :     if (*pszHeaderNext != '=')
     231             :     {
     232             :         // ISIS3 does not have anything after the end group/object keyword.
     233        1797 :         if (EQUAL(osName, "End_Group") || EQUAL(osName, "End_Object"))
     234        1796 :             return true;
     235             : 
     236           1 :         return false;
     237             :     }
     238             : 
     239       12795 :     pszHeaderNext++;
     240             : 
     241       12795 :     SkipWhite();
     242             : 
     243       12795 :     osValue = "";
     244       12795 :     bool bIsString = true;
     245             : 
     246             :     // Handle value lists like:
     247             :     // Name   = (Red, Red) or  {Red, Red} or even ({Red, Red}, {Red, Red})
     248       25590 :     CPLJSONArray oArray;
     249       12795 :     if (*pszHeaderNext == '(' || *pszHeaderNext == '{')
     250             :     {
     251         484 :         std::vector<char> oStackArrayBeginChar;
     252         484 :         CPLString osWord;
     253             : 
     254         484 :         oStackArrayBeginChar.push_back(*pszHeaderNext);
     255         484 :         osValue += *pszHeaderNext;
     256         484 :         pszHeaderNext++;
     257             : 
     258        1481 :         while (ReadWord(osWord, false, true, &bIsString))
     259             :         {
     260        1481 :             if (*pszHeaderNext == '(' || *pszHeaderNext == '{')
     261             :             {
     262           3 :                 oStackArrayBeginChar.push_back(*pszHeaderNext);
     263           3 :                 osValue += *pszHeaderNext;
     264           3 :                 pszHeaderNext++;
     265             :             }
     266             : 
     267             :             // TODO: we could probably do better with nested json arrays
     268             :             // instead of flattening when there are (( )) or ({ }) constructs
     269        1481 :             if (bIsString)
     270             :             {
     271        1049 :                 if (!(osWord.empty() &&
     272           8 :                       (*pszHeaderNext == '(' || *pszHeaderNext == '{' ||
     273           8 :                        *pszHeaderNext == ')' || *pszHeaderNext == '}')))
     274             :                 {
     275             :                     std::string osValueInArray =
     276        2074 :                         StripQuotesIfNeeded(osWord, false);
     277        1290 :                     if (!osValueInArray.empty() && osValueInArray == osWord &&
     278         253 :                         osValueInArray.back() == '>')
     279             :                     {
     280          50 :                         const auto nPosLeftBracket = osValueInArray.rfind('<');
     281          50 :                         if (nPosLeftBracket != std::string::npos)
     282             :                         {
     283             :                             const std::string osUnit = osValueInArray.substr(
     284          50 :                                 nPosLeftBracket + 1, osValueInArray.size() - 1 -
     285         100 :                                                          (nPosLeftBracket + 1));
     286          50 :                             osValueInArray.resize(nPosLeftBracket);
     287         200 :                             while (!osValueInArray.empty() &&
     288         100 :                                    osValueInArray.back() == ' ')
     289          50 :                                 osValueInArray.pop_back();
     290             : 
     291         100 :                             CPLJSONObject newObject;
     292          50 :                             if (CPLGetValueType(osValueInArray.c_str()) ==
     293             :                                 CPL_VALUE_STRING)
     294             :                             {
     295           0 :                                 newObject.Add("value", osValueInArray);
     296             :                             }
     297          50 :                             else if (CPLGetValueType(osValueInArray.c_str()) ==
     298             :                                      CPL_VALUE_INTEGER)
     299             :                             {
     300           6 :                                 newObject.Add("value",
     301             :                                               atoi(osValueInArray.c_str()));
     302             :                             }
     303             :                             else
     304             :                             {
     305          44 :                                 newObject.Add("value",
     306             :                                               CPLAtof(osValueInArray.c_str()));
     307             :                             }
     308          50 :                             newObject.Add("unit", osUnit);
     309          50 :                             oArray.Add(newObject);
     310             :                         }
     311             :                         else
     312             :                         {
     313           0 :                             oArray.Add(osValueInArray);
     314             :                         }
     315             :                     }
     316             :                     else
     317             :                     {
     318         987 :                         oArray.Add(osValueInArray);
     319             :                     }
     320             :                 }
     321             :             }
     322         440 :             else if (CPLGetValueType(osWord) == CPL_VALUE_INTEGER)
     323             :             {
     324         295 :                 oArray.Add(atoi(osWord));
     325             :             }
     326             :             else
     327             :             {
     328         145 :                 oArray.Add(CPLAtof(osWord));
     329             :             }
     330             : 
     331        1481 :             osValue += osWord;
     332        1494 :             while (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     333             :             {
     334          13 :                 pszHeaderNext++;
     335             :             }
     336             : 
     337        1481 :             if (*pszHeaderNext == ')')
     338             :             {
     339         474 :                 osValue += *pszHeaderNext;
     340         948 :                 if (oStackArrayBeginChar.empty() ||
     341         474 :                     oStackArrayBeginChar.back() != '(')
     342             :                 {
     343           1 :                     CPLDebug("PDS", "Unpaired ( ) for %s", osName.c_str());
     344           1 :                     return false;
     345             :                 }
     346         473 :                 oStackArrayBeginChar.pop_back();
     347         473 :                 pszHeaderNext++;
     348         473 :                 if (oStackArrayBeginChar.empty())
     349         472 :                     break;
     350             :             }
     351        1007 :             else if (*pszHeaderNext == '}')
     352             :             {
     353          13 :                 osValue += *pszHeaderNext;
     354          26 :                 if (oStackArrayBeginChar.empty() ||
     355          13 :                     oStackArrayBeginChar.back() != '{')
     356             :                 {
     357           1 :                     CPLDebug("PDS", "Unpaired { } for %s", osName.c_str());
     358           1 :                     return false;
     359             :                 }
     360          12 :                 oStackArrayBeginChar.pop_back();
     361          12 :                 pszHeaderNext++;
     362          12 :                 if (oStackArrayBeginChar.empty())
     363          10 :                     break;
     364             :             }
     365         994 :             else if (*pszHeaderNext == ',')
     366             :             {
     367         991 :                 osValue += *pszHeaderNext;
     368         991 :                 pszHeaderNext++;
     369             :                 // Do not use SkipWhite() here to avoid being confuse by
     370             :                 // constructs like
     371             :                 // FOO = (#123456,
     372             :                 //        #123456)
     373             :                 // where we could confuse the second line with a comment.
     374        3348 :                 while (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     375             :                 {
     376        2357 :                     pszHeaderNext++;
     377             :                 }
     378             :             }
     379         997 :             SkipWhite();
     380         482 :         }
     381             :     }
     382             : 
     383             :     else  // Handle more normal "single word" values.
     384             :     {
     385       12311 :         if (!ReadWord(osValue, m_bStripSurroundingQuotes, false, &bIsString))
     386           0 :             return false;
     387             :     }
     388             : 
     389       12793 :     SkipWhite();
     390             : 
     391       20632 :     const auto AddToCur = [&oCur, &osName](const CPLJSONObject &o)
     392             :     {
     393       20618 :         auto oExistingObjForName = oCur.GetObjNoSplitName(osName);
     394       10309 :         if (oExistingObjForName.IsValid())
     395             :         {
     396          10 :             if (oExistingObjForName["values"].GetType() ==
     397             :                 CPLJSONObject::Type::Array)
     398             :             {
     399           2 :                 oExistingObjForName["values"].ToArray().Add(o);
     400             :             }
     401             :             else
     402             :             {
     403          16 :                 CPLJSONArray ar;
     404           8 :                 ar.Add(oExistingObjForName);
     405           8 :                 ar.Add(o);
     406          16 :                 CPLJSONObject oObj;
     407           8 :                 oObj.Add("values", ar);
     408           8 :                 oCur.DeleteNoSplitName(osName);
     409           8 :                 oCur.AddNoSplitName(osName, std::move(oObj));
     410             :             }
     411             :         }
     412             :         else
     413             :         {
     414       10299 :             oCur.AddNoSplitName(osName, o);
     415             :         }
     416       10309 :     };
     417             : 
     418             :     // No units keyword?
     419       12793 :     if (*pszHeaderNext != '<')
     420             :     {
     421       12041 :         if (!EQUAL(osName, "OBJECT") && !EQUAL(osName, "GROUP"))
     422             :         {
     423        9557 :             if (oArray.Size() > 0)
     424             :             {
     425         478 :                 AddToCur(oArray);
     426             :             }
     427             :             else
     428             :             {
     429       18158 :                 CPLJSONObject oObj;
     430        9079 :                 if (bIsString)
     431             :                 {
     432        8672 :                     oObj = CPLJSONObject(StripQuotesIfNeeded(
     433        8672 :                         osValue, m_bStripSurroundingQuotes));
     434             :                 }
     435        4743 :                 else if (CPLGetValueType(osValue) == CPL_VALUE_INTEGER)
     436             :                 {
     437        2968 :                     oObj = CPLJSONObject(atoi(osValue));
     438             :                 }
     439             :                 else
     440             :                 {
     441        1775 :                     oObj = CPLJSONObject(CPLAtof(osValue));
     442             :                 }
     443        9079 :                 AddToCur(oObj);
     444             :             }
     445             :         }
     446       12041 :         return true;
     447             :     }
     448             : 
     449        1504 :     CPLString osValueNoUnit(osValue);
     450             :     // Append units keyword.  For lines that like like this:
     451             :     //  MAP_RESOLUTION               = 4.0 <PIXEL/DEGREE>
     452             : 
     453         752 :     osValue += " ";
     454             : 
     455        1504 :     CPLString osWord;
     456        1504 :     CPLString osUnit;
     457         752 :     while (ReadWord(osWord))
     458             :     {
     459         752 :         SkipWhite();
     460             : 
     461         752 :         osValue += osWord;
     462         752 :         osUnit = osWord;
     463         752 :         if (osWord.back() == '>')
     464         752 :             break;
     465             :     }
     466             : 
     467         752 :     if (osUnit[0] == '<')
     468         752 :         osUnit = osUnit.substr(1);
     469         752 :     if (!osUnit.empty() && osUnit.back() == '>')
     470         752 :         osUnit = osUnit.substr(0, osUnit.size() - 1);
     471             : 
     472         752 :     CPLJSONObject newObject;
     473             : 
     474         752 :     if (oArray.Size() > 0)
     475             :     {
     476           2 :         newObject.Add("value", oArray);
     477             :     }
     478             :     else
     479             :     {
     480         750 :         if (bIsString)
     481             :         {
     482          10 :             newObject.Add("value", osValueNoUnit);
     483             :         }
     484         740 :         else if (CPLGetValueType(osValueNoUnit) == CPL_VALUE_INTEGER)
     485             :         {
     486          44 :             newObject.Add("value", atoi(osValueNoUnit));
     487             :         }
     488             :         else
     489             :         {
     490         696 :             newObject.Add("value", CPLAtof(osValueNoUnit));
     491             :         }
     492             :     }
     493         752 :     newObject.Add("unit", osUnit);
     494         752 :     AddToCur(newObject);
     495             : 
     496         752 :     return true;
     497             : }
     498             : 
     499             : /************************************************************************/
     500             : /*                              ReadWord()                              */
     501             : /*  Returns TRUE on success                                             */
     502             : /************************************************************************/
     503             : 
     504       29479 : bool NASAKeywordHandler::ReadWord(CPLString &osWord,
     505             :                                   bool bStripSurroundingQuotes, bool bParseList,
     506             :                                   bool *pbIsString)
     507             : 
     508             : {
     509       29479 :     if (pbIsString)
     510       13792 :         *pbIsString = false;
     511       29479 :     osWord = "";
     512             : 
     513       29479 :     SkipWhite();
     514             : 
     515       29479 :     if (!(*pszHeaderNext != '\0' && *pszHeaderNext != '=' &&
     516       29479 :           !isspace(static_cast<unsigned char>(*pszHeaderNext))))
     517           0 :         return false;
     518             : 
     519             :     /* Extract a text string delimited by '\"' */
     520             :     /* Convert newlines (CR or LF) within quotes. While text strings
     521             :        support them as per ODL, the keyword list doesn't want them */
     522       29479 :     if (*pszHeaderNext == '"')
     523             :     {
     524        1948 :         if (pbIsString)
     525        1948 :             *pbIsString = true;
     526        1948 :         if (!bStripSurroundingQuotes)
     527        1928 :             osWord += *(pszHeaderNext);
     528        1948 :         pszHeaderNext++;
     529       28375 :         while (*pszHeaderNext != '"')
     530             :         {
     531       26427 :             if (*pszHeaderNext == '\0')
     532           0 :                 return false;
     533       26427 :             if (*pszHeaderNext == '\n')
     534             :             {
     535         121 :                 osWord += "\\n";
     536         121 :                 pszHeaderNext++;
     537         121 :                 continue;
     538             :             }
     539       26306 :             if (*pszHeaderNext == '\r')
     540             :             {
     541         118 :                 osWord += "\\r";
     542         118 :                 pszHeaderNext++;
     543         118 :                 continue;
     544             :             }
     545       26188 :             osWord += *(pszHeaderNext++);
     546             :         }
     547        1948 :         if (!bStripSurroundingQuotes)
     548        1928 :             osWord += *(pszHeaderNext);
     549        1948 :         pszHeaderNext++;
     550             : 
     551        1948 :         return true;
     552             :     }
     553             : 
     554             :     /* Extract a symbol string */
     555             :     /* These are expected to not have
     556             :        '\'' (delimiters),
     557             :        format effectors (should fit on a single line) or
     558             :        control characters.
     559             :     */
     560       27531 :     if (*pszHeaderNext == '\'')
     561             :     {
     562           8 :         if (pbIsString)
     563           8 :             *pbIsString = true;
     564           8 :         if (!bStripSurroundingQuotes)
     565           8 :             osWord += *(pszHeaderNext);
     566           8 :         pszHeaderNext++;
     567          32 :         while (*pszHeaderNext != '\'')
     568             :         {
     569          24 :             if (*pszHeaderNext == '\0')
     570           0 :                 return false;
     571             : 
     572          24 :             osWord += *(pszHeaderNext++);
     573             :         }
     574           8 :         if (!bStripSurroundingQuotes)
     575           8 :             osWord += *(pszHeaderNext);
     576           8 :         pszHeaderNext++;
     577           8 :         return true;
     578             :     }
     579             : 
     580             :     /*
     581             :      * Extract normal text.  Terminated by '=' or whitespace.
     582             :      *
     583             :      * A special exception is that a line may terminate with a '-'
     584             :      * which is taken as a line extender, and we suck up white space to new
     585             :      * text.
     586             :      */
     587      245283 :     while (
     588      272806 :         *pszHeaderNext != '\0' && *pszHeaderNext != '=' &&
     589      270607 :         ((bParseList && *pszHeaderNext != ',' && *pszHeaderNext != '(' &&
     590        5661 :           *pszHeaderNext != ')' && *pszHeaderNext != '{' &&
     591      270607 :           *pszHeaderNext != '}') ||
     592      264400 :          (!bParseList && !isspace(static_cast<unsigned char>(*pszHeaderNext)))))
     593             :     {
     594      245283 :         osWord += *pszHeaderNext;
     595      245283 :         pszHeaderNext++;
     596             : 
     597      245283 :         if (*pszHeaderNext == '-' &&
     598         145 :             (pszHeaderNext[1] == 10 || pszHeaderNext[1] == 13))
     599             :         {
     600           4 :             pszHeaderNext += 2;
     601           4 :             SkipWhite();
     602             :         }
     603             :     }
     604             : 
     605       27523 :     if (pbIsString)
     606       11836 :         *pbIsString = CPLGetValueType(osWord) == CPL_VALUE_STRING;
     607             : 
     608       27523 :     return true;
     609             : }
     610             : 
     611             : /************************************************************************/
     612             : /*                             SkipWhite()                              */
     613             : /*  Skip white spaces and C style comments                              */
     614             : /************************************************************************/
     615             : 
     616      229882 : void NASAKeywordHandler::SkipWhite()
     617             : 
     618             : {
     619             :     for (; true;)
     620             :     {
     621             :         // Skip C style comments
     622      229882 :         if (*pszHeaderNext == '/' && pszHeaderNext[1] == '*')
     623             :         {
     624         336 :             pszHeaderNext += 2;
     625             : 
     626       17999 :             while (*pszHeaderNext != '\0' &&
     627       17999 :                    (*pszHeaderNext != '*' || pszHeaderNext[1] != '/'))
     628             :             {
     629       17663 :                 pszHeaderNext++;
     630             :             }
     631         336 :             if (*pszHeaderNext == '\0')
     632           0 :                 return;
     633             : 
     634         336 :             pszHeaderNext += 2;
     635             : 
     636             :             // consume till end of line.
     637             :             // reduce sensibility to a label error
     638         336 :             while (*pszHeaderNext != '\0' && *pszHeaderNext != 10 &&
     639         294 :                    *pszHeaderNext != 13)
     640             :             {
     641           0 :                 pszHeaderNext++;
     642             :             }
     643         336 :             continue;
     644             :         }
     645             : 
     646             :         // Skip # style comments
     647      229546 :         if ((*pszHeaderNext == 10 || *pszHeaderNext == 13 ||
     648      209808 :              *pszHeaderNext == ' ' || *pszHeaderNext == '\t') &&
     649      157791 :             pszHeaderNext[1] == '#')
     650             :         {
     651          83 :             pszHeaderNext += 2;
     652             : 
     653             :             // consume till end of line.
     654        4138 :             while (*pszHeaderNext != '\0' && *pszHeaderNext != 10 &&
     655        4055 :                    *pszHeaderNext != 13)
     656             :             {
     657        4055 :                 pszHeaderNext++;
     658             :             }
     659          83 :             continue;
     660             :         }
     661             : 
     662             :         // Skip white space (newline, space, tab, etc )
     663      229463 :         if (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     664             :         {
     665      157708 :             pszHeaderNext++;
     666      157708 :             continue;
     667             :         }
     668             : 
     669             :         // not white space, return.
     670       71755 :         return;
     671             :     }
     672             : }
     673             : 
     674             : /************************************************************************/
     675             : /*                             GetKeyword()                             */
     676             : /************************************************************************/
     677             : 
     678        8338 : const char *NASAKeywordHandler::GetKeyword(const char *pszPath,
     679             :                                            const char *pszDefault)
     680             : 
     681             : {
     682        8338 :     return aosKeywordList.FetchNameValueDef(pszPath, pszDefault);
     683             : }
     684             : 
     685             : /************************************************************************/
     686             : /*                           GetKeywordList()                           */
     687             : /************************************************************************/
     688             : 
     689           0 : char **NASAKeywordHandler::GetKeywordList()
     690             : {
     691           0 :     return aosKeywordList.List();
     692             : }
     693             : 
     694             : /************************************************************************/
     695             : /*                             StealJSon()                              */
     696             : /************************************************************************/
     697             : 
     698         334 : CPLJSONObject NASAKeywordHandler::GetJsonObject() const
     699             : {
     700         334 :     return oJSon;
     701             : }
     702             : 
     703             : //! @endcond

Generated by: LCOV version 1.14