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-01-08 02:20:26 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         474 : NASAKeywordHandler::NASAKeywordHandler()
      56         474 :     : pszHeaderNext(nullptr), m_bStripSurroundingQuotes(false)
      57             : {
      58         474 :     oJSon.Deinit();
      59         474 : }
      60             : 
      61             : /************************************************************************/
      62             : /*                        ~NASAKeywordHandler()                         */
      63             : /************************************************************************/
      64             : 
      65         474 : NASAKeywordHandler::~NASAKeywordHandler()
      66             : 
      67             : {
      68         474 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                               Ingest()                               */
      72             : /************************************************************************/
      73             : 
      74         312 : 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         312 :     if (VSIFSeekL(fp, nOffset, SEEK_SET) != 0)
      81           0 :         return false;
      82             : 
      83         624 :     std::string osHeaderText;
      84             :     for (; true;)
      85             :     {
      86             :         char szChunk[513];
      87             : 
      88        3654 :         int nBytesRead = static_cast<int>(VSIFReadL(szChunk, 1, 512, fp));
      89             : 
      90        3654 :         szChunk[nBytesRead] = '\0';
      91        3654 :         osHeaderText += szChunk;
      92             : 
      93        3654 :         if (nBytesRead < 512)
      94         165 :             break;
      95             : 
      96        3489 :         const char *pszCheck = nullptr;
      97        3489 :         if (osHeaderText.size() > 520)
      98         499 :             pszCheck = osHeaderText.c_str() + (osHeaderText.size() - 520);
      99             :         else
     100        2990 :             pszCheck = szChunk;
     101             : 
     102        3489 :         if (strstr(pszCheck, "\r\nEND\r\n") != nullptr ||
     103        3474 :             strstr(pszCheck, "\nEND\n") != nullptr ||
     104        3465 :             strstr(pszCheck, "\r\nEnd\r\n") != nullptr ||
     105        3465 :             strstr(pszCheck, "\nEnd\n") != nullptr)
     106             :             break;
     107        3342 :     }
     108             : 
     109         312 :     return Parse(osHeaderText.c_str());
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                               Parse()                                */
     114             : /************************************************************************/
     115             : 
     116         343 : bool NASAKeywordHandler::Parse(const char *pszStr)
     117             : 
     118             : {
     119         343 :     pszHeaderNext = pszStr;
     120             : 
     121             :     /* -------------------------------------------------------------------- */
     122             :     /*      Process name/value pairs, keeping track of a "path stack".      */
     123             :     /* -------------------------------------------------------------------- */
     124         343 :     oJSon = CPLJSONObject();
     125         343 :     return ReadGroup("", oJSon, 0);
     126             : }
     127             : 
     128             : /************************************************************************/
     129             : /*                             ReadGroup()                              */
     130             : /************************************************************************/
     131             : 
     132        2785 : bool NASAKeywordHandler::ReadGroup(const std::string &osPathPrefix,
     133             :                                    CPLJSONObject &oCur, int nRecLevel)
     134             : 
     135             : {
     136        2785 :     if (osPathPrefix.size() > 256)
     137             :     {
     138           0 :         CPLError(CE_Failure, CPLE_NotSupported, "Too big prefix for GROUP");
     139           0 :         return false;
     140             :     }
     141        2785 :     if (nRecLevel == 100)
     142           0 :         return false;
     143             :     for (; true;)
     144             :     {
     145       14690 :         CPLString osName, osValue;
     146       14690 :         if (!ReadPair(osName, osValue, oCur))
     147           3 :             return false;
     148             : 
     149       14687 :         if (EQUAL(osName, "OBJECT") || EQUAL(osName, "GROUP"))
     150             :         {
     151        2442 :             CPLJSONObject oNewGroup;
     152        2442 :             oNewGroup.Add("_type",
     153        2442 :                           EQUAL(osName, "OBJECT") ? "object" : "group");
     154        2442 :             if (!ReadGroup((osPathPrefix + osValue + ".").c_str(), oNewGroup,
     155             :                            nRecLevel + 1))
     156             :             {
     157           0 :                 return false;
     158             :             }
     159        7326 :             CPLJSONObject oName = oNewGroup["Name"];
     160        2442 :             if (oName.GetType() == CPLJSONObject::Type::String)
     161             :             {
     162         285 :                 oCur.Add(osValue + "_" + oName.ToString(), oNewGroup);
     163         285 :                 oNewGroup.Add("_container_name", osValue);
     164             :             }
     165        2157 :             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        2153 :                 oCur.Add(osValue, oNewGroup);
     178             :             }
     179             :         }
     180       23115 :         else if (EQUAL(osName, "END") || EQUAL(osName, "END_GROUP") ||
     181       10870 :                  EQUAL(osName, "END_OBJECT"))
     182             :         {
     183        2782 :             return true;
     184             :         }
     185             :         else
     186             :         {
     187        9463 :             osName = osPathPrefix + osName;
     188        9463 :             aosKeywordList.AddNameValue(osName, osValue);
     189             :         }
     190       11905 :     }
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                        StripQuotesIfNeeded()                         */
     195             : /************************************************************************/
     196             : 
     197        5191 : static CPLString StripQuotesIfNeeded(const CPLString &osWord,
     198             :                                      bool bQuotesAlreadyRemoved)
     199             : {
     200        5191 :     if (bQuotesAlreadyRemoved || osWord.size() < 2 || osWord[0] != '"')
     201        3372 :         return osWord;
     202        3638 :     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       14690 : bool NASAKeywordHandler::ReadPair(CPLString &osName, CPLString &osValue,
     214             :                                   CPLJSONObject &oCur)
     215             : 
     216             : {
     217       14690 :     osName = "";
     218       14690 :     osValue = "";
     219             : 
     220       14690 :     if (!ReadWord(osName))
     221           0 :         return false;
     222             : 
     223       14690 :     SkipWhite();
     224             : 
     225       14690 :     if (EQUAL(osName, "END"))
     226         340 :         return true;
     227             : 
     228       14350 :     if (*pszHeaderNext != '=')
     229             :     {
     230             :         // ISIS3 does not have anything after the end group/object keyword.
     231        1792 :         if (EQUAL(osName, "End_Group") || EQUAL(osName, "End_Object"))
     232        1791 :             return true;
     233             : 
     234           1 :         return false;
     235             :     }
     236             : 
     237       12558 :     pszHeaderNext++;
     238             : 
     239       12558 :     SkipWhite();
     240             : 
     241       12558 :     osValue = "";
     242       12558 :     bool bIsString = true;
     243             : 
     244             :     // Handle value lists like:
     245             :     // Name   = (Red, Red) or  {Red, Red} or even ({Red, Red}, {Red, Red})
     246       25116 :     CPLJSONArray oArray;
     247       12558 :     if (*pszHeaderNext == '(' || *pszHeaderNext == '{')
     248             :     {
     249         438 :         std::vector<char> oStackArrayBeginChar;
     250         438 :         CPLString osWord;
     251             : 
     252         438 :         oStackArrayBeginChar.push_back(*pszHeaderNext);
     253         438 :         osValue += *pszHeaderNext;
     254         438 :         pszHeaderNext++;
     255             : 
     256        1335 :         while (ReadWord(osWord, false, true, &bIsString))
     257             :         {
     258        1335 :             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        1335 :             if (bIsString)
     268             :             {
     269         973 :                 if (!(osWord.empty() &&
     270           8 :                       (*pszHeaderNext == '(' || *pszHeaderNext == '{' ||
     271           8 :                        *pszHeaderNext == ')' || *pszHeaderNext == '}')))
     272             :                 {
     273             :                     std::string osValueInArray =
     274        1922 :                         StripQuotesIfNeeded(osWord, false);
     275        1214 :                     if (!osValueInArray.empty() && osValueInArray == osWord &&
     276         253 :                         osValueInArray.back() == '>')
     277             :                     {
     278          50 :                         const auto nPosLeftBracket = osValueInArray.rfind('<');
     279          50 :                         if (nPosLeftBracket != std::string::npos)
     280             :                         {
     281             :                             const std::string osUnit = osValueInArray.substr(
     282          50 :                                 nPosLeftBracket + 1, osValueInArray.size() - 1 -
     283         100 :                                                          (nPosLeftBracket + 1));
     284          50 :                             osValueInArray.resize(nPosLeftBracket);
     285         200 :                             while (!osValueInArray.empty() &&
     286         100 :                                    osValueInArray.back() == ' ')
     287          50 :                                 osValueInArray.pop_back();
     288             : 
     289         100 :                             CPLJSONObject newObject;
     290          50 :                             if (CPLGetValueType(osValueInArray.c_str()) ==
     291             :                                 CPL_VALUE_STRING)
     292             :                             {
     293           0 :                                 newObject.Add("value", osValueInArray);
     294             :                             }
     295          50 :                             else if (CPLGetValueType(osValueInArray.c_str()) ==
     296             :                                      CPL_VALUE_INTEGER)
     297             :                             {
     298           6 :                                 newObject.Add("value",
     299             :                                               atoi(osValueInArray.c_str()));
     300             :                             }
     301             :                             else
     302             :                             {
     303          44 :                                 newObject.Add("value",
     304             :                                               CPLAtof(osValueInArray.c_str()));
     305             :                             }
     306          50 :                             newObject.Add("unit", osUnit);
     307          50 :                             oArray.Add(newObject);
     308             :                         }
     309             :                         else
     310             :                         {
     311           0 :                             oArray.Add(osValueInArray);
     312             :                         }
     313             :                     }
     314             :                     else
     315             :                     {
     316         911 :                         oArray.Add(osValueInArray);
     317             :                     }
     318             :                 }
     319             :             }
     320         370 :             else if (CPLGetValueType(osWord) == CPL_VALUE_INTEGER)
     321             :             {
     322         235 :                 oArray.Add(atoi(osWord));
     323             :             }
     324             :             else
     325             :             {
     326         135 :                 oArray.Add(CPLAtof(osWord));
     327             :             }
     328             : 
     329        1335 :             osValue += osWord;
     330        1348 :             while (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     331             :             {
     332          13 :                 pszHeaderNext++;
     333             :             }
     334             : 
     335        1335 :             if (*pszHeaderNext == ')')
     336             :             {
     337         428 :                 osValue += *pszHeaderNext;
     338         856 :                 if (oStackArrayBeginChar.empty() ||
     339         428 :                     oStackArrayBeginChar.back() != '(')
     340             :                 {
     341           1 :                     CPLDebug("PDS", "Unpaired ( ) for %s", osName.c_str());
     342           1 :                     return false;
     343             :                 }
     344         427 :                 oStackArrayBeginChar.pop_back();
     345         427 :                 pszHeaderNext++;
     346         427 :                 if (oStackArrayBeginChar.empty())
     347         426 :                     break;
     348             :             }
     349         907 :             else if (*pszHeaderNext == '}')
     350             :             {
     351          13 :                 osValue += *pszHeaderNext;
     352          26 :                 if (oStackArrayBeginChar.empty() ||
     353          13 :                     oStackArrayBeginChar.back() != '{')
     354             :                 {
     355           1 :                     CPLDebug("PDS", "Unpaired { } for %s", osName.c_str());
     356           1 :                     return false;
     357             :                 }
     358          12 :                 oStackArrayBeginChar.pop_back();
     359          12 :                 pszHeaderNext++;
     360          12 :                 if (oStackArrayBeginChar.empty())
     361          10 :                     break;
     362             :             }
     363         894 :             else if (*pszHeaderNext == ',')
     364             :             {
     365         891 :                 osValue += *pszHeaderNext;
     366         891 :                 pszHeaderNext++;
     367             :                 // Do not use SkipWhite() here to avoid being confuse by
     368             :                 // constructs like
     369             :                 // FOO = (#123456,
     370             :                 //        #123456)
     371             :                 // where we could confuse the second line with a comment.
     372        3248 :                 while (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     373             :                 {
     374        2357 :                     pszHeaderNext++;
     375             :                 }
     376             :             }
     377         897 :             SkipWhite();
     378         436 :         }
     379             :     }
     380             : 
     381             :     else  // Handle more normal "single word" values.
     382             :     {
     383       12120 :         if (!ReadWord(osValue, m_bStripSurroundingQuotes, false, &bIsString))
     384           0 :             return false;
     385             :     }
     386             : 
     387       12556 :     SkipWhite();
     388             : 
     389       20234 :     const auto AddToCur = [&oCur, &osName](const CPLJSONObject &o)
     390             :     {
     391       20228 :         auto oExistingObjForName = oCur[osName];
     392       10114 :         if (oExistingObjForName.IsValid())
     393             :         {
     394          10 :             if (oExistingObjForName["values"].GetType() ==
     395             :                 CPLJSONObject::Type::Array)
     396             :             {
     397           2 :                 oExistingObjForName["values"].ToArray().Add(o);
     398             :             }
     399             :             else
     400             :             {
     401          16 :                 CPLJSONArray ar;
     402           8 :                 ar.Add(oExistingObjForName);
     403           8 :                 ar.Add(o);
     404           8 :                 CPLJSONObject oObj;
     405           8 :                 oObj.Add("values", ar);
     406           8 :                 oCur.Delete(osName);
     407           8 :                 oCur[osName] = oObj;
     408             :             }
     409             :         }
     410             :         else
     411             :         {
     412       10104 :             oCur.Add(osName, o);
     413             :         }
     414       10114 :     };
     415             : 
     416             :     // No units keyword?
     417       12556 :     if (*pszHeaderNext != '<')
     418             :     {
     419       11806 :         if (!EQUAL(osName, "OBJECT") && !EQUAL(osName, "GROUP"))
     420             :         {
     421        9364 :             if (oArray.Size() > 0)
     422             :             {
     423         432 :                 AddToCur(oArray);
     424             :             }
     425             :             else
     426             :             {
     427       17864 :                 CPLJSONObject oObj;
     428        8932 :                 if (bIsString)
     429             :                 {
     430        8460 :                     oObj = CPLJSONObject(StripQuotesIfNeeded(
     431        8460 :                         osValue, m_bStripSurroundingQuotes));
     432             :                 }
     433        4702 :                 else if (CPLGetValueType(osValue) == CPL_VALUE_INTEGER)
     434             :                 {
     435        2931 :                     oObj = CPLJSONObject(atoi(osValue));
     436             :                 }
     437             :                 else
     438             :                 {
     439        1771 :                     oObj = CPLJSONObject(CPLAtof(osValue));
     440             :                 }
     441        8932 :                 AddToCur(oObj);
     442             :             }
     443             :         }
     444       11806 :         return true;
     445             :     }
     446             : 
     447        1500 :     CPLString osValueNoUnit(osValue);
     448             :     // Append units keyword.  For lines that like like this:
     449             :     //  MAP_RESOLUTION               = 4.0 <PIXEL/DEGREE>
     450             : 
     451         750 :     osValue += " ";
     452             : 
     453        1500 :     CPLString osWord;
     454        1500 :     CPLString osUnit;
     455         750 :     while (ReadWord(osWord))
     456             :     {
     457         750 :         SkipWhite();
     458             : 
     459         750 :         osValue += osWord;
     460         750 :         osUnit = osWord;
     461         750 :         if (osWord.back() == '>')
     462         750 :             break;
     463             :     }
     464             : 
     465         750 :     if (osUnit[0] == '<')
     466         750 :         osUnit = osUnit.substr(1);
     467         750 :     if (!osUnit.empty() && osUnit.back() == '>')
     468         750 :         osUnit = osUnit.substr(0, osUnit.size() - 1);
     469             : 
     470         750 :     CPLJSONObject newObject;
     471             : 
     472         750 :     if (oArray.Size() > 0)
     473             :     {
     474           2 :         newObject.Add("value", oArray);
     475             :     }
     476             :     else
     477             :     {
     478         748 :         if (bIsString)
     479             :         {
     480          10 :             newObject.Add("value", osValueNoUnit);
     481             :         }
     482         738 :         else if (CPLGetValueType(osValueNoUnit) == CPL_VALUE_INTEGER)
     483             :         {
     484          42 :             newObject.Add("value", atoi(osValueNoUnit));
     485             :         }
     486             :         else
     487             :         {
     488         696 :             newObject.Add("value", CPLAtof(osValueNoUnit));
     489             :         }
     490             :     }
     491         750 :     newObject.Add("unit", osUnit);
     492         750 :     AddToCur(newObject);
     493             : 
     494         750 :     return true;
     495             : }
     496             : 
     497             : /************************************************************************/
     498             : /*                              ReadWord()                              */
     499             : /*  Returns TRUE on success                                             */
     500             : /************************************************************************/
     501             : 
     502       28895 : bool NASAKeywordHandler::ReadWord(CPLString &osWord,
     503             :                                   bool bStripSurroundingQuotes, bool bParseList,
     504             :                                   bool *pbIsString)
     505             : 
     506             : {
     507       28895 :     if (pbIsString)
     508       13455 :         *pbIsString = false;
     509       28895 :     osWord = "";
     510             : 
     511       28895 :     SkipWhite();
     512             : 
     513       28895 :     if (!(*pszHeaderNext != '\0' && *pszHeaderNext != '=' &&
     514       28895 :           !isspace(static_cast<unsigned char>(*pszHeaderNext))))
     515           0 :         return false;
     516             : 
     517             :     /* Extract a text string delimited by '\"' */
     518             :     /* Convert newlines (CR or LF) within quotes. While text strings
     519             :        support them as per ODL, the keyword list doesn't want them */
     520       28895 :     if (*pszHeaderNext == '"')
     521             :     {
     522        1841 :         if (pbIsString)
     523        1841 :             *pbIsString = true;
     524        1841 :         if (!bStripSurroundingQuotes)
     525        1821 :             osWord += *(pszHeaderNext);
     526        1841 :         pszHeaderNext++;
     527       27500 :         while (*pszHeaderNext != '"')
     528             :         {
     529       25659 :             if (*pszHeaderNext == '\0')
     530           0 :                 return false;
     531       25659 :             if (*pszHeaderNext == '\n')
     532             :             {
     533         121 :                 osWord += "\\n";
     534         121 :                 pszHeaderNext++;
     535         121 :                 continue;
     536             :             }
     537       25538 :             if (*pszHeaderNext == '\r')
     538             :             {
     539         118 :                 osWord += "\\r";
     540         118 :                 pszHeaderNext++;
     541         118 :                 continue;
     542             :             }
     543       25420 :             osWord += *(pszHeaderNext++);
     544             :         }
     545        1841 :         if (!bStripSurroundingQuotes)
     546        1821 :             osWord += *(pszHeaderNext);
     547        1841 :         pszHeaderNext++;
     548             : 
     549        1841 :         return true;
     550             :     }
     551             : 
     552             :     /* Extract a symbol string */
     553             :     /* These are expected to not have
     554             :        '\'' (delimiters),
     555             :        format effectors (should fit on a single line) or
     556             :        control characters.
     557             :     */
     558       27054 :     if (*pszHeaderNext == '\'')
     559             :     {
     560           8 :         if (pbIsString)
     561           8 :             *pbIsString = true;
     562           8 :         if (!bStripSurroundingQuotes)
     563           8 :             osWord += *(pszHeaderNext);
     564           8 :         pszHeaderNext++;
     565          32 :         while (*pszHeaderNext != '\'')
     566             :         {
     567          24 :             if (*pszHeaderNext == '\0')
     568           0 :                 return false;
     569             : 
     570          24 :             osWord += *(pszHeaderNext++);
     571             :         }
     572           8 :         if (!bStripSurroundingQuotes)
     573           8 :             osWord += *(pszHeaderNext);
     574           8 :         pszHeaderNext++;
     575           8 :         return true;
     576             :     }
     577             : 
     578             :     /*
     579             :      * Extract normal text.  Terminated by '=' or whitespace.
     580             :      *
     581             :      * A special exception is that a line may terminate with a '-'
     582             :      * which is taken as a line extender, and we suck up white space to new
     583             :      * text.
     584             :      */
     585      241111 :     while (
     586      268157 :         *pszHeaderNext != '\0' && *pszHeaderNext != '=' &&
     587      266152 :         ((bParseList && *pszHeaderNext != ',' && *pszHeaderNext != '(' &&
     588        5375 :           *pszHeaderNext != ')' && *pszHeaderNext != '{' &&
     589      266152 :           *pszHeaderNext != '}') ||
     590      260283 :          (!bParseList && !isspace(static_cast<unsigned char>(*pszHeaderNext)))))
     591             :     {
     592      241111 :         osWord += *pszHeaderNext;
     593      241111 :         pszHeaderNext++;
     594             : 
     595      241111 :         if (*pszHeaderNext == '-' &&
     596         145 :             (pszHeaderNext[1] == 10 || pszHeaderNext[1] == 13))
     597             :         {
     598           4 :             pszHeaderNext += 2;
     599           4 :             SkipWhite();
     600             :         }
     601             :     }
     602             : 
     603       27046 :     if (pbIsString)
     604       11606 :         *pbIsString = CPLGetValueType(osWord) == CPL_VALUE_STRING;
     605             : 
     606       27046 :     return true;
     607             : }
     608             : 
     609             : /************************************************************************/
     610             : /*                             SkipWhite()                              */
     611             : /*  Skip white spaces and C style comments                              */
     612             : /************************************************************************/
     613             : 
     614      227055 : void NASAKeywordHandler::SkipWhite()
     615             : 
     616             : {
     617             :     for (; true;)
     618             :     {
     619             :         // Skip C style comments
     620      227055 :         if (*pszHeaderNext == '/' && pszHeaderNext[1] == '*')
     621             :         {
     622         333 :             pszHeaderNext += 2;
     623             : 
     624       17886 :             while (*pszHeaderNext != '\0' &&
     625       17886 :                    (*pszHeaderNext != '*' || pszHeaderNext[1] != '/'))
     626             :             {
     627       17553 :                 pszHeaderNext++;
     628             :             }
     629         333 :             if (*pszHeaderNext == '\0')
     630           0 :                 return;
     631             : 
     632         333 :             pszHeaderNext += 2;
     633             : 
     634             :             // consume till end of line.
     635             :             // reduce sensibility to a label error
     636         333 :             while (*pszHeaderNext != '\0' && *pszHeaderNext != 10 &&
     637         294 :                    *pszHeaderNext != 13)
     638             :             {
     639           0 :                 pszHeaderNext++;
     640             :             }
     641         333 :             continue;
     642             :         }
     643             : 
     644             :         // Skip # style comments
     645      226722 :         if ((*pszHeaderNext == 10 || *pszHeaderNext == 13 ||
     646      207235 :              *pszHeaderNext == ' ' || *pszHeaderNext == '\t') &&
     647      156372 :             pszHeaderNext[1] == '#')
     648             :         {
     649          83 :             pszHeaderNext += 2;
     650             : 
     651             :             // consume till end of line.
     652        4138 :             while (*pszHeaderNext != '\0' && *pszHeaderNext != 10 &&
     653        4055 :                    *pszHeaderNext != 13)
     654             :             {
     655        4055 :                 pszHeaderNext++;
     656             :             }
     657          83 :             continue;
     658             :         }
     659             : 
     660             :         // Skip white space (newline, space, tab, etc )
     661      226639 :         if (isspace(static_cast<unsigned char>(*pszHeaderNext)))
     662             :         {
     663      156289 :             pszHeaderNext++;
     664      156289 :             continue;
     665             :         }
     666             : 
     667             :         // not white space, return.
     668       70350 :         return;
     669             :     }
     670             : }
     671             : 
     672             : /************************************************************************/
     673             : /*                             GetKeyword()                             */
     674             : /************************************************************************/
     675             : 
     676        8259 : const char *NASAKeywordHandler::GetKeyword(const char *pszPath,
     677             :                                            const char *pszDefault)
     678             : 
     679             : {
     680        8259 :     return aosKeywordList.FetchNameValueDef(pszPath, pszDefault);
     681             : }
     682             : 
     683             : /************************************************************************/
     684             : /*                             GetKeywordList()                         */
     685             : /************************************************************************/
     686             : 
     687           0 : char **NASAKeywordHandler::GetKeywordList()
     688             : {
     689           0 :     return aosKeywordList.List();
     690             : }
     691             : 
     692             : /************************************************************************/
     693             : /*                               StealJSon()                            */
     694             : /************************************************************************/
     695             : 
     696         331 : CPLJSONObject NASAKeywordHandler::GetJsonObject() const
     697             : {
     698         331 :     return oJSon;
     699             : }
     700             : 
     701             : //! @endcond

Generated by: LCOV version 1.14