LCOV - code coverage report
Current view: top level - frmts/iso8211 - 8211createfromxml.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 155 187 82.9 %
Date: 2026-04-19 18:43:50 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           1 : int main(int nArgc, char *papszArgv[])
      23             : {
      24           1 :     const char *pszFilename = nullptr;
      25           1 :     const char *pszOutFilename = nullptr;
      26             : 
      27             :     /* -------------------------------------------------------------------- */
      28             :     /*      Check arguments.                                                */
      29             :     /* -------------------------------------------------------------------- */
      30           3 :     for (int iArg = 1; iArg < nArgc; iArg++)
      31             :     {
      32           2 :         if (pszFilename == nullptr)
      33             :         {
      34           1 :             pszFilename = papszArgv[iArg];
      35             :         }
      36           1 :         else if (pszOutFilename == nullptr)
      37             :         {
      38           1 :             pszOutFilename = papszArgv[iArg];
      39             :         }
      40             :         else
      41             :         {
      42           0 :             pszFilename = nullptr;
      43           0 :             break;
      44             :         }
      45             :     }
      46             : 
      47           1 :     if (pszFilename == nullptr)
      48             :     {
      49           0 :         printf("Usage: 8211createfromxml filename.xml outfilename\n");
      50           0 :         exit(1);
      51             :     }
      52             : 
      53           1 :     CPLXMLNode *poRoot = CPLParseXMLFile(pszFilename);
      54           1 :     if (poRoot == nullptr)
      55             :     {
      56           0 :         fprintf(stderr, "Cannot parse XML file '%s'\n", pszFilename);
      57           0 :         exit(1);
      58             :     }
      59             : 
      60           1 :     CPLXMLNode *poXMLDDFModule = CPLSearchXMLNode(poRoot, "=DDFModule");
      61           1 :     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           1 :     CPLXMLNode *psIter = poXMLDDFModule->psChild;
      70           1 :     int nSizeFieldTag = 0;
      71         101 :     while (psIter != nullptr)
      72             :     {
      73         100 :         if (psIter->eType == CXT_Element &&
      74          90 :             strcmp(psIter->pszValue, "DDFFieldDefn") == 0)
      75             :         {
      76          20 :             const char *pszTag = CPLGetXMLValue(psIter, "tag", "");
      77          20 :             if (nSizeFieldTag == 0)
      78           1 :                 nSizeFieldTag = (int)strlen(pszTag);
      79          19 :             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         100 :         psIter = psIter->psNext;
      86             :     }
      87             : 
      88           1 :     char chInterchangeLevel = '3';
      89           1 :     chInterchangeLevel =
      90           1 :         CPLGetXMLValue(poXMLDDFModule, "_interchangeLevel",
      91             :                        CPLSPrintf("%c", chInterchangeLevel))[0];
      92             : 
      93           1 :     char chLeaderIden = 'L';
      94           1 :     chLeaderIden = CPLGetXMLValue(poXMLDDFModule, "_leaderIden",
      95             :                                   CPLSPrintf("%c", chLeaderIden))[0];
      96             : 
      97           1 :     char chCodeExtensionIndicator = 'E';
      98           1 :     chCodeExtensionIndicator =
      99           1 :         CPLGetXMLValue(poXMLDDFModule, "_inlineCodeExtensionIndicator",
     100             :                        CPLSPrintf("%c", chCodeExtensionIndicator))[0];
     101             : 
     102           1 :     char chVersionNumber = '1';
     103           1 :     chVersionNumber = CPLGetXMLValue(poXMLDDFModule, "_versionNumber",
     104             :                                      CPLSPrintf("%c", chVersionNumber))[0];
     105             : 
     106           1 :     char chAppIndicator = ' ';
     107           1 :     chAppIndicator = CPLGetXMLValue(poXMLDDFModule, "_appIndicator",
     108             :                                     CPLSPrintf("%c", chAppIndicator))[0];
     109             : 
     110             :     char szExtendedCharSet[4];
     111           1 :     snprintf(szExtendedCharSet, sizeof(szExtendedCharSet), "%s",
     112             :              CPLGetXMLValue(poXMLDDFModule, "_extendedCharSet", " ! "));
     113           1 :     int nSizeFieldLength = 3;
     114           1 :     nSizeFieldLength = atoi(CPLGetXMLValue(poXMLDDFModule, "_sizeFieldLength",
     115             :                                            CPLSPrintf("%d", nSizeFieldLength)));
     116             : 
     117           1 :     int nSizeFieldPos = 4;
     118           1 :     nSizeFieldPos = atoi(CPLGetXMLValue(poXMLDDFModule, "_sizeFieldPos",
     119             :                                         CPLSPrintf("%d", nSizeFieldPos)));
     120           1 :     nSizeFieldTag = atoi(CPLGetXMLValue(poXMLDDFModule, "_sizeFieldTag",
     121             :                                         CPLSPrintf("%d", nSizeFieldTag)));
     122             : 
     123           1 :     DDFModule oModule;
     124           1 :     oModule.Initialize(
     125             :         chInterchangeLevel, chLeaderIden, chCodeExtensionIndicator,
     126             :         chVersionNumber, chAppIndicator,
     127           0 :         std::array<char, 3>{szExtendedCharSet[0], szExtendedCharSet[1],
     128           1 :                             szExtendedCharSet[2]},
     129             :         nSizeFieldLength, nSizeFieldPos, nSizeFieldTag);
     130           1 :     oModule.SetFieldControlLength(atoi(
     131             :         CPLGetXMLValue(poXMLDDFModule, "_fieldControlLength",
     132             :                        CPLSPrintf("%d", oModule.GetFieldControlLength()))));
     133             : 
     134           1 :     bool bCreated = false;
     135             : 
     136             :     // Create DDFFieldDefn and DDFRecord elements.
     137           1 :     psIter = poXMLDDFModule->psChild;
     138         101 :     while (psIter != nullptr)
     139             :     {
     140         100 :         if (psIter->eType == CXT_Element &&
     141          90 :             strcmp(psIter->pszValue, "DDFFieldDefn") == 0)
     142             :         {
     143          20 :             auto poFDefn = std::make_unique<DDFFieldDefn>();
     144             : 
     145          20 :             DDF_data_struct_code eStructCode = dsc_elementary;
     146             :             const char *pszStructCode =
     147          20 :                 CPLGetXMLValue(psIter, "dataStructCode", "");
     148          20 :             if (strcmp(pszStructCode, "elementary") == 0)
     149           2 :                 eStructCode = dsc_elementary;
     150          18 :             else if (strcmp(pszStructCode, "vector") == 0)
     151          10 :                 eStructCode = dsc_vector;
     152           8 :             else if (strcmp(pszStructCode, "array") == 0)
     153           8 :                 eStructCode = dsc_array;
     154           0 :             else if (strcmp(pszStructCode, "concatenated") == 0)
     155           0 :                 eStructCode = dsc_concatenated;
     156             : 
     157          20 :             DDF_data_type_code eTypeCode = dtc_char_string;
     158             :             const char *pszTypeCode =
     159          20 :                 CPLGetXMLValue(psIter, "dataTypeCode", "");
     160          20 :             if (strcmp(pszTypeCode, "char_string") == 0)
     161           1 :                 eTypeCode = dtc_char_string;
     162          19 :             else if (strcmp(pszTypeCode, "implicit_point") == 0)
     163           0 :                 eTypeCode = dtc_implicit_point;
     164          19 :             else if (strcmp(pszTypeCode, "explicit_point") == 0)
     165           0 :                 eTypeCode = dtc_explicit_point;
     166          19 :             else if (strcmp(pszTypeCode, "explicit_point_scaled") == 0)
     167           0 :                 eTypeCode = dtc_explicit_point_scaled;
     168          19 :             else if (strcmp(pszTypeCode, "char_bit_string") == 0)
     169           0 :                 eTypeCode = dtc_char_bit_string;
     170          19 :             else if (strcmp(pszTypeCode, "bit_string") == 0)
     171           3 :                 eTypeCode = dtc_bit_string;
     172          16 :             else if (strcmp(pszTypeCode, "mixed_data_type") == 0)
     173          16 :                 eTypeCode = dtc_mixed_data_type;
     174             : 
     175             :             const char *pszFormatControls =
     176          20 :                 CPLGetXMLValue(psIter, "formatControls", nullptr);
     177             :             const char *pszArrayDescr =
     178          20 :                 CPLGetXMLValue(psIter, "arrayDescr", nullptr);
     179          20 :             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          20 :             if (!poFDefn->Create(CPLGetXMLValue(psIter, "tag", ""),
     188             :                                  CPLGetXMLValue(psIter, "fieldName", ""),
     189             :                                  pszArrayDescr, eStructCode, eTypeCode,
     190             :                                  pszFormatControls))
     191             :             {
     192           0 :                 exit(1);
     193             :             }
     194             : 
     195          20 :             if (!pszArrayDescr && !pszFormatControls)
     196             :             {
     197           0 :                 CPLXMLNode *psSubIter = psIter->psChild;
     198           0 :                 while (psSubIter != nullptr)
     199             :                 {
     200           0 :                     if (psSubIter->eType == CXT_Element &&
     201           0 :                         strcmp(psSubIter->pszValue, "DDFSubfieldDefn") == 0)
     202             :                     {
     203           0 :                         poFDefn->AddSubfield(
     204             :                             CPLGetXMLValue(psSubIter, "name", ""),
     205             :                             CPLGetXMLValue(psSubIter, "format", ""));
     206             :                     }
     207           0 :                     psSubIter = psSubIter->psNext;
     208             :                 }
     209             :             }
     210             : 
     211          20 :             oModule.AddField(std::move(poFDefn));
     212             :         }
     213          80 :         else if (psIter->eType == CXT_Element &&
     214          70 :                  strcmp(psIter->pszValue, "DDFRecord") == 0)
     215             :         {
     216             :             // const bool bFirstRecord = !bCreated;
     217          70 :             if (!bCreated)
     218             :             {
     219           1 :                 oModule.Create(pszOutFilename);
     220           1 :                 bCreated = true;
     221             :             }
     222             : 
     223          70 :             DDFRecord *poRec = new DDFRecord(&oModule);
     224         140 :             std::map<std::string, int> oMapField;
     225             : 
     226             :             // if( !bFirstRecord )
     227             :             //     poRec->SetReuseHeader(atoi(
     228             :             //         CPLGetXMLValue(psIter, "reuseHeader",
     229             :             //         CPLSPrintf("%d", poRec->GetReuseHeader()))));
     230          70 :             poRec->SetSizeFieldLength(atoi(
     231             :                 CPLGetXMLValue(psIter, "_sizeFieldLength",
     232             :                                CPLSPrintf("%d", poRec->GetSizeFieldLength()))));
     233          70 :             poRec->SetSizeFieldPos(atoi(
     234             :                 CPLGetXMLValue(psIter, "_sizeFieldPos",
     235             :                                CPLSPrintf("%d", poRec->GetSizeFieldPos()))));
     236          70 :             poRec->SetSizeFieldTag(atoi(
     237             :                 CPLGetXMLValue(psIter, "_sizeFieldTag",
     238             :                                CPLSPrintf("%d", poRec->GetSizeFieldTag()))));
     239             : 
     240          70 :             CPLXMLNode *psSubIter = psIter->psChild;
     241         633 :             while (psSubIter != nullptr)
     242             :             {
     243         563 :                 if (psSubIter->eType == CXT_Element &&
     244         283 :                     strcmp(psSubIter->pszValue, "DDFField") == 0)
     245             :                 {
     246             :                     const char *pszFieldName =
     247         283 :                         CPLGetXMLValue(psSubIter, "name", "");
     248             :                     DDFFieldDefn *poFieldDefn =
     249         283 :                         oModule.FindFieldDefn(pszFieldName);
     250         283 :                     if (poFieldDefn == nullptr)
     251             :                     {
     252           0 :                         fprintf(stderr, "Can't find field '%s'\n",
     253             :                                 pszFieldName);
     254           0 :                         exit(1);
     255             :                     }
     256             : 
     257         283 :                     int nFieldOcc = oMapField[pszFieldName];
     258         283 :                     oMapField[pszFieldName]++;
     259             : 
     260         283 :                     DDFField *poField = poRec->AddField(poFieldDefn);
     261             :                     const char *pszValue =
     262         283 :                         CPLGetXMLValue(psSubIter, "value", nullptr);
     263         283 :                     if (pszValue != nullptr && STARTS_WITH(pszValue, "0x"))
     264             :                     {
     265          70 :                         pszValue += 2;
     266          70 :                         int nDataLen = (int)strlen(pszValue) / 2;
     267          70 :                         char *pabyData = (char *)CPLMalloc(nDataLen);
     268         210 :                         for (int i = 0; i < nDataLen; i++)
     269             :                         {
     270             :                             char c;
     271             :                             int nHigh, nLow;
     272         140 :                             c = pszValue[2 * i];
     273         140 :                             if (c >= 'A' && c <= 'F')
     274           0 :                                 nHigh = 10 + c - 'A';
     275             :                             else
     276         140 :                                 nHigh = c - '0';
     277         140 :                             c = pszValue[2 * i + 1];
     278         140 :                             if (c >= 'A' && c <= 'F')
     279          24 :                                 nLow = 10 + c - 'A';
     280             :                             else
     281         116 :                                 nLow = c - '0';
     282         140 :                             pabyData[i] = (nHigh << 4) + nLow;
     283             :                         }
     284          70 :                         poRec->SetFieldRaw(poField, nFieldOcc,
     285             :                                            (const char *)pabyData, nDataLen);
     286          70 :                         CPLFree(pabyData);
     287             :                     }
     288             :                     else
     289             :                     {
     290         213 :                         CPLXMLNode *psSubfieldIter = psSubIter->psChild;
     291         426 :                         std::map<std::string, int> oMapSubfield;
     292        1795 :                         while (psSubfieldIter != nullptr)
     293             :                         {
     294        1582 :                             if (psSubfieldIter->eType == CXT_Element &&
     295        1317 :                                 strcmp(psSubfieldIter->pszValue,
     296             :                                        "DDFSubfield") == 0)
     297             :                             {
     298             :                                 const char *pszSubfieldName =
     299        1317 :                                     CPLGetXMLValue(psSubfieldIter, "name", "");
     300             :                                 const char *pszSubfieldType =
     301        1317 :                                     CPLGetXMLValue(psSubfieldIter, "type", "");
     302             :                                 const char *pszSubfieldValue =
     303        1317 :                                     CPLGetXMLValue(psSubfieldIter, nullptr, "");
     304        1317 :                                 int nOcc = oMapSubfield[pszSubfieldName];
     305        1317 :                                 oMapSubfield[pszSubfieldName]++;
     306        1317 :                                 if (strcmp(pszSubfieldType, "float") == 0)
     307             :                                 {
     308           1 :                                     poRec->SetFloatSubfield(
     309             :                                         pszFieldName, nFieldOcc,
     310             :                                         pszSubfieldName, nOcc,
     311             :                                         CPLAtof(pszSubfieldValue));
     312             :                                 }
     313        1316 :                                 else if (strcmp(pszSubfieldType, "integer") ==
     314             :                                          0)
     315             :                                 {
     316        1124 :                                     poRec->SetIntSubfield(
     317             :                                         pszFieldName, nFieldOcc,
     318             :                                         pszSubfieldName, nOcc,
     319             :                                         atoi(pszSubfieldValue));
     320             :                                 }
     321         192 :                                 else if (strcmp(pszSubfieldType, "string") == 0)
     322             :                                 {
     323          57 :                                     poRec->SetStringSubfield(
     324             :                                         pszFieldName, nFieldOcc,
     325             :                                         pszSubfieldName, nOcc,
     326             :                                         pszSubfieldValue);
     327             :                                 }
     328         135 :                                 else if (strcmp(pszSubfieldType, "binary") ==
     329         135 :                                              0 &&
     330         135 :                                          STARTS_WITH(pszSubfieldValue, "0x"))
     331             :                                 {
     332         135 :                                     pszSubfieldValue += 2;
     333         135 :                                     int nDataLen =
     334         135 :                                         (int)strlen(pszSubfieldValue) / 2;
     335             :                                     char *pabyData =
     336         135 :                                         (char *)CPLMalloc(nDataLen);
     337         810 :                                     for (int i = 0; i < nDataLen; i++)
     338             :                                     {
     339             :                                         int nHigh;
     340             :                                         int nLow;
     341         675 :                                         char c = pszSubfieldValue[2 * i];
     342         675 :                                         if (c >= 'A' && c <= 'F')
     343           0 :                                             nHigh = 10 + c - 'A';
     344             :                                         else
     345         675 :                                             nHigh = c - '0';
     346         675 :                                         c = pszSubfieldValue[2 * i + 1];
     347         675 :                                         if (c >= 'A' && c <= 'F')
     348          43 :                                             nLow = 10 + c - 'A';
     349             :                                         else
     350         632 :                                             nLow = c - '0';
     351         675 :                                         pabyData[i] = (nHigh << 4) + nLow;
     352             :                                     }
     353         135 :                                     poRec->SetStringSubfield(
     354             :                                         pszFieldName, nFieldOcc,
     355             :                                         pszSubfieldName, nOcc, pabyData,
     356             :                                         nDataLen);
     357         135 :                                     CPLFree(pabyData);
     358             :                                 }
     359             :                             }
     360        1582 :                             psSubfieldIter = psSubfieldIter->psNext;
     361             :                         }
     362             :                     }
     363             :                 }
     364         563 :                 psSubIter = psSubIter->psNext;
     365             :             }
     366             : 
     367          70 :             poRec->Write();
     368          70 :             delete poRec;
     369             :         }
     370             : 
     371         100 :         psIter = psIter->psNext;
     372             :     }
     373             : 
     374           1 :     CPLDestroyXMLNode(poRoot);
     375             : 
     376           1 :     oModule.Close();
     377             : 
     378           1 :     return 0;
     379             : }

Generated by: LCOV version 1.14