LCOV - code coverage report
Current view: top level - frmts/iso8211 - 8211createfromxml.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 161 198 81.3 %
Date: 2026-05-29 23:25:07 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ISO8211 library
       4             :  * Purpose:  Create a 8211 file from a XML dump file generated by "8211dump
       5             :  *-xml" Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_conv.h"
      14             : #include "cpl_minixml.h"
      15             : #include "cpl_string.h"
      16             : #include "iso8211.h"
      17             : 
      18             : #include <array>
      19             : #include <map>
      20             : #include <string>
      21             : 
      22         209 : int main(int nArgc, char *papszArgv[])
      23             : {
      24         209 :     const char *pszFilename = nullptr;
      25         209 :     const char *pszOutFilename = nullptr;
      26             : 
      27             :     /* -------------------------------------------------------------------- */
      28             :     /*      Check arguments.                                                */
      29             :     /* -------------------------------------------------------------------- */
      30         627 :     for (int iArg = 1; iArg < nArgc; iArg++)
      31             :     {
      32         418 :         if (pszFilename == nullptr)
      33             :         {
      34         209 :             pszFilename = papszArgv[iArg];
      35             :         }
      36         209 :         else if (pszOutFilename == nullptr)
      37             :         {
      38         209 :             pszOutFilename = papszArgv[iArg];
      39             :         }
      40             :         else
      41             :         {
      42           0 :             pszFilename = nullptr;
      43           0 :             break;
      44             :         }
      45             :     }
      46             : 
      47         209 :     if (pszFilename == nullptr)
      48             :     {
      49           0 :         printf("Usage: 8211createfromxml filename.xml outfilename\n");
      50           0 :         exit(1);
      51             :     }
      52             : 
      53         209 :     CPLXMLNode *poRoot = CPLParseXMLFile(pszFilename);
      54         209 :     if (poRoot == nullptr)
      55             :     {
      56           0 :         fprintf(stderr, "Cannot parse XML file '%s'\n", pszFilename);
      57           0 :         exit(1);
      58             :     }
      59             : 
      60         209 :     CPLXMLNode *poXMLDDFModule = CPLSearchXMLNode(poRoot, "=DDFModule");
      61         209 :     if (poXMLDDFModule == nullptr)
      62             :     {
      63           0 :         fprintf(stderr, "Cannot find DDFModule node in XML file '%s'\n",
      64             :                 pszFilename);
      65           0 :         exit(1);
      66             :     }
      67             : 
      68             :     /* Compute the size of the DDFField tag */
      69         209 :     CPLXMLNode *psIter = poXMLDDFModule->psChild;
      70         209 :     int nSizeFieldTag = 0;
      71        6510 :     while (psIter != nullptr)
      72             :     {
      73        6301 :         if (psIter->eType == CXT_Element &&
      74        3999 :             strcmp(psIter->pszValue, "DDFFieldDefn") == 0)
      75             :         {
      76        2798 :             const char *pszTag = CPLGetXMLValue(psIter, "tag", "");
      77        2798 :             if (nSizeFieldTag == 0)
      78         209 :                 nSizeFieldTag = (int)strlen(pszTag);
      79        2589 :             else if (nSizeFieldTag != (int)strlen(pszTag))
      80             :             {
      81           0 :                 fprintf(stderr, "All fields have not the same tag size\n");
      82           0 :                 exit(1);
      83             :             }
      84             :         }
      85        6301 :         psIter = psIter->psNext;
      86             :     }
      87             : 
      88         209 :     char chInterchangeLevel = '3';
      89         209 :     chInterchangeLevel =
      90         209 :         CPLGetXMLValue(poXMLDDFModule, "_interchangeLevel",
      91             :                        CPLSPrintf("%c", chInterchangeLevel))[0];
      92             : 
      93         209 :     char chLeaderIden = 'L';
      94         209 :     chLeaderIden = CPLGetXMLValue(poXMLDDFModule, "_leaderIden",
      95             :                                   CPLSPrintf("%c", chLeaderIden))[0];
      96             : 
      97         209 :     char chCodeExtensionIndicator = 'E';
      98         209 :     chCodeExtensionIndicator =
      99         209 :         CPLGetXMLValue(poXMLDDFModule, "_inlineCodeExtensionIndicator",
     100             :                        CPLSPrintf("%c", chCodeExtensionIndicator))[0];
     101             : 
     102         209 :     char chVersionNumber = '1';
     103         209 :     chVersionNumber = CPLGetXMLValue(poXMLDDFModule, "_versionNumber",
     104             :                                      CPLSPrintf("%c", chVersionNumber))[0];
     105             : 
     106         209 :     char chAppIndicator = ' ';
     107         209 :     chAppIndicator = CPLGetXMLValue(poXMLDDFModule, "_appIndicator",
     108             :                                     CPLSPrintf("%c", chAppIndicator))[0];
     109             : 
     110             :     char szExtendedCharSet[4];
     111         209 :     snprintf(szExtendedCharSet, sizeof(szExtendedCharSet), "%s",
     112             :              CPLGetXMLValue(poXMLDDFModule, "_extendedCharSet", " ! "));
     113         209 :     int nSizeFieldLength = 3;
     114         209 :     nSizeFieldLength = atoi(CPLGetXMLValue(poXMLDDFModule, "_sizeFieldLength",
     115             :                                            CPLSPrintf("%d", nSizeFieldLength)));
     116             : 
     117         209 :     int nSizeFieldPos = 4;
     118         209 :     nSizeFieldPos = atoi(CPLGetXMLValue(poXMLDDFModule, "_sizeFieldPos",
     119             :                                         CPLSPrintf("%d", nSizeFieldPos)));
     120         209 :     nSizeFieldTag = atoi(CPLGetXMLValue(poXMLDDFModule, "_sizeFieldTag",
     121             :                                         CPLSPrintf("%d", nSizeFieldTag)));
     122             : 
     123         209 :     DDFModule oModule;
     124         209 :     oModule.Initialize(
     125             :         chInterchangeLevel, chLeaderIden, chCodeExtensionIndicator,
     126             :         chVersionNumber, chAppIndicator,
     127           0 :         std::array<char, 3>{szExtendedCharSet[0], szExtendedCharSet[1],
     128         209 :                             szExtendedCharSet[2]},
     129             :         nSizeFieldLength, nSizeFieldPos, nSizeFieldTag);
     130         209 :     oModule.SetFieldControlLength(atoi(
     131             :         CPLGetXMLValue(poXMLDDFModule, "_fieldControlLength",
     132             :                        CPLSPrintf("%d", oModule.GetFieldControlLength()))));
     133             : 
     134         209 :     bool bCreated = false;
     135             : 
     136             :     // Create DDFFieldDefn and DDFRecord elements.
     137         209 :     psIter = poXMLDDFModule->psChild;
     138        6510 :     while (psIter != nullptr)
     139             :     {
     140        6301 :         if (psIter->eType == CXT_Element &&
     141        3999 :             strcmp(psIter->pszValue, "DDFFieldDefn") == 0)
     142             :         {
     143        2798 :             auto poFDefn = std::make_unique<DDFFieldDefn>();
     144             : 
     145        2798 :             DDF_data_struct_code eStructCode = dsc_elementary;
     146             :             const char *pszStructCode =
     147        2798 :                 CPLGetXMLValue(psIter, "dataStructCode", "");
     148        2798 :             if (strcmp(pszStructCode, "elementary") == 0)
     149         206 :                 eStructCode = dsc_elementary;
     150        2592 :             else if (strcmp(pszStructCode, "vector") == 0)
     151        1332 :                 eStructCode = dsc_vector;
     152        1260 :             else if (strcmp(pszStructCode, "array") == 0)
     153         956 :                 eStructCode = dsc_array;
     154         304 :             else if (strcmp(pszStructCode, "concatenated") == 0)
     155         304 :                 eStructCode = dsc_concatenated;
     156             : 
     157        2798 :             DDF_data_type_code eTypeCode = dtc_char_string;
     158             :             const char *pszTypeCode =
     159        2798 :                 CPLGetXMLValue(psIter, "dataTypeCode", "");
     160        2798 :             if (strcmp(pszTypeCode, "char_string") == 0)
     161         205 :                 eTypeCode = dtc_char_string;
     162        2593 :             else if (strcmp(pszTypeCode, "implicit_point") == 0)
     163        1288 :                 eTypeCode = dtc_implicit_point;
     164        1305 :             else if (strcmp(pszTypeCode, "explicit_point") == 0)
     165           0 :                 eTypeCode = dtc_explicit_point;
     166        1305 :             else if (strcmp(pszTypeCode, "explicit_point_scaled") == 0)
     167           0 :                 eTypeCode = dtc_explicit_point_scaled;
     168        1305 :             else if (strcmp(pszTypeCode, "char_bit_string") == 0)
     169           0 :                 eTypeCode = dtc_char_bit_string;
     170        1305 :             else if (strcmp(pszTypeCode, "bit_string") == 0)
     171           3 :                 eTypeCode = dtc_bit_string;
     172        1302 :             else if (strcmp(pszTypeCode, "mixed_data_type") == 0)
     173        1301 :                 eTypeCode = dtc_mixed_data_type;
     174             : 
     175             :             const char *pszFormatControls =
     176        2798 :                 CPLGetXMLValue(psIter, "formatControls", nullptr);
     177             :             const char *pszArrayDescr =
     178        2798 :                 CPLGetXMLValue(psIter, "arrayDescr", nullptr);
     179        2798 :             if (!pszArrayDescr && !pszFormatControls)
     180             :             {
     181           0 :                 if (eStructCode == dsc_vector)
     182           0 :                     pszArrayDescr = "";
     183           0 :                 else if (eStructCode == dsc_array)
     184           0 :                     pszArrayDescr = "*";
     185             :             }
     186             : 
     187        2798 :             if (!poFDefn->Create(CPLGetXMLValue(psIter, "tag", ""),
     188             :                                  CPLGetXMLValue(psIter, "fieldName", ""),
     189             :                                  pszArrayDescr, eStructCode, eTypeCode,
     190             :                                  pszFormatControls))
     191             :             {
     192           0 :                 exit(1);
     193             :             }
     194             : 
     195             :             const char *pszEscapeSequence =
     196        2798 :                 CPLGetXMLValue(psIter, "escapeSequence", nullptr);
     197        2798 :             if (pszEscapeSequence)
     198        2724 :                 poFDefn->SetEscapeSequence(pszEscapeSequence);
     199             : 
     200        2798 :             if (!pszArrayDescr && !pszFormatControls)
     201             :             {
     202           0 :                 CPLXMLNode *psSubIter = psIter->psChild;
     203           0 :                 while (psSubIter != nullptr)
     204             :                 {
     205           0 :                     if (psSubIter->eType == CXT_Element &&
     206           0 :                         strcmp(psSubIter->pszValue, "DDFSubfieldDefn") == 0)
     207             :                     {
     208           0 :                         poFDefn->AddSubfield(
     209             :                             CPLGetXMLValue(psSubIter, "name", ""),
     210             :                             CPLGetXMLValue(psSubIter, "format", ""));
     211             :                     }
     212           0 :                     psSubIter = psSubIter->psNext;
     213             :                 }
     214             :             }
     215             : 
     216        2798 :             oModule.AddField(std::move(poFDefn));
     217             :         }
     218        3503 :         else if (psIter->eType == CXT_Element &&
     219        1201 :                  strcmp(psIter->pszValue, "DDFRecord") == 0)
     220             :         {
     221             :             // const bool bFirstRecord = !bCreated;
     222        1201 :             if (!bCreated)
     223             :             {
     224         209 :                 oModule.Create(pszOutFilename);
     225         209 :                 bCreated = true;
     226             :             }
     227             : 
     228        1201 :             DDFRecord *poRec = new DDFRecord(&oModule);
     229        2402 :             std::map<std::string, int> oMapField;
     230             : 
     231             :             // if( !bFirstRecord )
     232             :             //     poRec->SetReuseHeader(atoi(
     233             :             //         CPLGetXMLValue(psIter, "reuseHeader",
     234             :             //         CPLSPrintf("%d", poRec->GetReuseHeader()))));
     235        1201 :             poRec->SetSizeFieldLength(atoi(
     236             :                 CPLGetXMLValue(psIter, "_sizeFieldLength",
     237             :                                CPLSPrintf("%d", poRec->GetSizeFieldLength()))));
     238        1201 :             poRec->SetSizeFieldPos(atoi(
     239             :                 CPLGetXMLValue(psIter, "_sizeFieldPos",
     240             :                                CPLSPrintf("%d", poRec->GetSizeFieldPos()))));
     241        1201 :             poRec->SetSizeFieldTag(atoi(
     242             :                 CPLGetXMLValue(psIter, "_sizeFieldTag",
     243             :                                CPLSPrintf("%d", poRec->GetSizeFieldTag()))));
     244             : 
     245        1201 :             CPLXMLNode *psSubIter = psIter->psChild;
     246        5210 :             while (psSubIter != nullptr)
     247             :             {
     248        4009 :                 if (psSubIter->eType == CXT_Element &&
     249        3721 :                     strcmp(psSubIter->pszValue, "DDFField") == 0)
     250             :                 {
     251             :                     const char *pszFieldName =
     252        3721 :                         CPLGetXMLValue(psSubIter, "name", "");
     253             :                     DDFFieldDefn *poFieldDefn =
     254        3721 :                         oModule.FindFieldDefn(pszFieldName);
     255        3721 :                     if (poFieldDefn == nullptr)
     256             :                     {
     257           0 :                         fprintf(stderr, "Can't find field '%s'\n",
     258             :                                 pszFieldName);
     259           0 :                         exit(1);
     260             :                     }
     261             : 
     262        3721 :                     int nFieldOcc = oMapField[pszFieldName];
     263        3721 :                     oMapField[pszFieldName]++;
     264             : 
     265        3721 :                     DDFField *poField = poRec->AddField(poFieldDefn);
     266             :                     const char *pszValue =
     267        3721 :                         CPLGetXMLValue(psSubIter, "value", nullptr);
     268        3721 :                     if (pszValue != nullptr && STARTS_WITH(pszValue, "0x"))
     269             :                     {
     270          70 :                         pszValue += 2;
     271          70 :                         int nDataLen = (int)strlen(pszValue) / 2;
     272          70 :                         char *pabyData = (char *)CPLMalloc(nDataLen);
     273         210 :                         for (int i = 0; i < nDataLen; i++)
     274             :                         {
     275             :                             char c;
     276             :                             int nHigh, nLow;
     277         140 :                             c = pszValue[2 * i];
     278         140 :                             if (c >= 'A' && c <= 'F')
     279           0 :                                 nHigh = 10 + c - 'A';
     280             :                             else
     281         140 :                                 nHigh = c - '0';
     282         140 :                             c = pszValue[2 * i + 1];
     283         140 :                             if (c >= 'A' && c <= 'F')
     284          24 :                                 nLow = 10 + c - 'A';
     285             :                             else
     286         116 :                                 nLow = c - '0';
     287         140 :                             pabyData[i] = (nHigh << 4) + nLow;
     288             :                         }
     289          70 :                         poRec->SetFieldRaw(poField, nFieldOcc,
     290             :                                            (const char *)pabyData, nDataLen);
     291          70 :                         CPLFree(pabyData);
     292             :                     }
     293             :                     else
     294             :                     {
     295        3651 :                         CPLXMLNode *psSubfieldIter = psSubIter->psChild;
     296        7302 :                         std::map<std::string, int> oMapSubfield;
     297       31547 :                         while (psSubfieldIter != nullptr)
     298             :                         {
     299       27896 :                             if (psSubfieldIter->eType == CXT_Element &&
     300       23317 :                                 strcmp(psSubfieldIter->pszValue,
     301             :                                        "DDFSubfield") == 0)
     302             :                             {
     303             :                                 const char *pszSubfieldName =
     304       23317 :                                     CPLGetXMLValue(psSubfieldIter, "name", "");
     305             :                                 const char *pszSubfieldType =
     306       23317 :                                     CPLGetXMLValue(psSubfieldIter, "type", "");
     307             :                                 const char *pszSubfieldValue =
     308       23317 :                                     CPLGetXMLValue(psSubfieldIter, nullptr, "");
     309       23317 :                                 int nOcc = oMapSubfield[pszSubfieldName];
     310       23317 :                                 oMapSubfield[pszSubfieldName]++;
     311       23317 :                                 if (strcmp(pszSubfieldType, "float") == 0)
     312             :                                 {
     313         620 :                                     if (!poRec->SetFloatSubfield(
     314             :                                             pszFieldName, nFieldOcc,
     315             :                                             pszSubfieldName, nOcc,
     316             :                                             CPLAtof(pszSubfieldValue)))
     317             :                                     {
     318           0 :                                         CPLError(
     319             :                                             CE_Failure, CPLE_AppDefined,
     320             :                                             "SetFloatSubfield(%s, %s) failed",
     321             :                                             pszFieldName, pszSubfieldName);
     322           0 :                                         exit(1);
     323             :                                     }
     324             :                                 }
     325       22697 :                                 else if (strcmp(pszSubfieldType, "integer") ==
     326             :                                          0)
     327             :                                 {
     328       17706 :                                     if (!poRec->SetIntSubfield(
     329             :                                             pszFieldName, nFieldOcc,
     330             :                                             pszSubfieldName, nOcc,
     331             :                                             atoi(pszSubfieldValue)))
     332             :                                     {
     333           0 :                                         CPLError(
     334             :                                             CE_Failure, CPLE_AppDefined,
     335             :                                             "SetIntSubfield(%s, %s) failed",
     336             :                                             pszFieldName, pszSubfieldName);
     337           0 :                                         exit(1);
     338             :                                     }
     339             :                                 }
     340        4991 :                                 else if (strcmp(pszSubfieldType, "string") == 0)
     341             :                                 {
     342        4856 :                                     if (!poRec->SetStringSubfield(
     343             :                                             pszFieldName, nFieldOcc,
     344             :                                             pszSubfieldName, nOcc,
     345             :                                             pszSubfieldValue))
     346             :                                     {
     347           0 :                                         CPLError(
     348             :                                             CE_Failure, CPLE_AppDefined,
     349             :                                             "SetStringSubfield(%s, %s) failed",
     350             :                                             pszFieldName, pszSubfieldName);
     351           0 :                                         exit(1);
     352             :                                     }
     353             :                                 }
     354         135 :                                 else if (strcmp(pszSubfieldType, "binary") ==
     355         135 :                                              0 &&
     356         135 :                                          STARTS_WITH(pszSubfieldValue, "0x"))
     357             :                                 {
     358         135 :                                     pszSubfieldValue += 2;
     359         135 :                                     int nDataLen =
     360         135 :                                         (int)strlen(pszSubfieldValue) / 2;
     361             :                                     char *pabyData =
     362         135 :                                         (char *)CPLMalloc(nDataLen);
     363         810 :                                     for (int i = 0; i < nDataLen; i++)
     364             :                                     {
     365             :                                         int nHigh;
     366             :                                         int nLow;
     367         675 :                                         char c = pszSubfieldValue[2 * i];
     368         675 :                                         if (c >= 'A' && c <= 'F')
     369           0 :                                             nHigh = 10 + c - 'A';
     370             :                                         else
     371         675 :                                             nHigh = c - '0';
     372         675 :                                         c = pszSubfieldValue[2 * i + 1];
     373         675 :                                         if (c >= 'A' && c <= 'F')
     374          43 :                                             nLow = 10 + c - 'A';
     375             :                                         else
     376         632 :                                             nLow = c - '0';
     377         675 :                                         pabyData[i] = (nHigh << 4) + nLow;
     378             :                                     }
     379         135 :                                     if (!poRec->SetStringSubfield(
     380             :                                             pszFieldName, nFieldOcc,
     381             :                                             pszSubfieldName, nOcc, pabyData,
     382             :                                             nDataLen))
     383             :                                     {
     384           0 :                                         CPLError(
     385             :                                             CE_Failure, CPLE_AppDefined,
     386             :                                             "SetStringSubfield(%s, %s) failed",
     387             :                                             pszFieldName, pszSubfieldName);
     388           0 :                                         exit(1);
     389             :                                     }
     390         135 :                                     CPLFree(pabyData);
     391             :                                 }
     392             :                             }
     393       27896 :                             psSubfieldIter = psSubfieldIter->psNext;
     394             :                         }
     395             :                     }
     396             :                 }
     397        4009 :                 psSubIter = psSubIter->psNext;
     398             :             }
     399             : 
     400        1201 :             poRec->Write();
     401        1201 :             delete poRec;
     402             :         }
     403             : 
     404        6301 :         psIter = psIter->psNext;
     405             :     }
     406             : 
     407         209 :     CPLDestroyXMLNode(poRoot);
     408             : 
     409         209 :     oModule.Close();
     410             : 
     411         209 :     return 0;
     412             : }

Generated by: LCOV version 1.14