1 /******************************************************************************
2  * $Id: 8211createfromxml.cpp 27942 2014-11-11 00:57:41Z rouault $
3  *
4  * Project:  ISO8211 library
5  * Purpose:  Create a 8211 file from a XML dump file generated by "8211dump -xml"
6  * Author:   Even Rouault <even dot rouault at mines-paris dot org>
7  *
8  ******************************************************************************
9  * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "cpl_minixml.h"
31 #include "iso8211.h"
32 #include <map>
33 #include <string>
34 
35 CPL_CVSID("$Id: 8211createfromxml.cpp 27942 2014-11-11 00:57:41Z rouault $");
36 
main(int nArgc,char * papszArgv[])37 int main(int nArgc, char* papszArgv[])
38 {
39     const char  *pszFilename = NULL, *pszOutFilename = NULL;
40     DDFModule  oModule;
41 
42 /* -------------------------------------------------------------------- */
43 /*      Check arguments.                                                */
44 /* -------------------------------------------------------------------- */
45     for( int iArg = 1; iArg < nArgc; iArg++ )
46     {
47         if( pszFilename == NULL )
48             pszFilename = papszArgv[iArg];
49         else if( pszOutFilename == NULL )
50             pszOutFilename = papszArgv[iArg];
51         else
52         {
53             pszFilename = NULL;
54             break;
55         }
56     }
57 
58     if( pszFilename == NULL )
59     {
60         printf( "Usage: 8211createfromxml filename.xml outfilename\n" );
61         exit( 1 );
62     }
63 
64     CPLXMLNode* poRoot = CPLParseXMLFile( pszFilename );
65     if( poRoot == NULL )
66     {
67         fprintf(stderr, "Cannot parse XML file '%s'\n", pszFilename);
68         exit( 1 );
69     }
70 
71     CPLXMLNode* poXMLDDFModule = CPLSearchXMLNode(poRoot, "=DDFModule");
72     if( poXMLDDFModule == NULL )
73     {
74         fprintf(stderr, "Cannot find DDFModule node in XML file '%s'\n", pszFilename);
75         exit( 1 );
76     }
77 
78     /* Compute the size of the DDFField tag */
79     CPLXMLNode* psIter = poXMLDDFModule->psChild;
80     int nSizeFieldTag = 0;
81     while( psIter != NULL )
82     {
83         if( psIter->eType == CXT_Element &&
84             strcmp(psIter->pszValue, "DDFFieldDefn") == 0 )
85         {
86             const char* pszTag = CPLGetXMLValue(psIter, "tag", "");
87             if( nSizeFieldTag == 0 )
88                 nSizeFieldTag = (int)strlen(pszTag);
89             else if( nSizeFieldTag != (int)strlen(pszTag) )
90             {
91                 fprintf(stderr, "All fields have not the same tag size\n");
92                 exit( 1 );
93             }
94         }
95         psIter = psIter->psNext;
96     }
97 
98     char chInterchangeLevel = '3';
99     char chLeaderIden = 'L';
100     char chCodeExtensionIndicator = 'E';
101     char chVersionNumber = '1';
102     char chAppIndicator = ' ';
103     const char *pszExtendedCharSet = " ! ";
104     int nSizeFieldLength = 3;
105     int nSizeFieldPos = 4;
106 
107     oModule.Initialize(chInterchangeLevel,
108                        chLeaderIden,
109                        chCodeExtensionIndicator,
110                        chVersionNumber,
111                        chAppIndicator,
112                        pszExtendedCharSet,
113                        nSizeFieldLength,
114                        nSizeFieldPos,
115                        nSizeFieldTag);
116 
117     int bCreated = FALSE;
118 
119     /* Create DDFFieldDefn and DDFRecord elements */
120     psIter = poXMLDDFModule->psChild;
121     while( psIter != NULL )
122     {
123         if( psIter->eType == CXT_Element &&
124             strcmp(psIter->pszValue, "DDFFieldDefn") == 0 )
125         {
126             DDFFieldDefn* poFDefn = new DDFFieldDefn();
127 
128             DDF_data_struct_code eStructCode = dsc_elementary;
129             const char* pszStructCode = CPLGetXMLValue(psIter, "dataStructCode", "");
130             if( strcmp(pszStructCode, "elementary") == 0 ) eStructCode = dsc_elementary;
131             else if( strcmp(pszStructCode, "vector") == 0 ) eStructCode = dsc_vector;
132             else if( strcmp(pszStructCode, "array") == 0 ) eStructCode = dsc_array;
133             else if( strcmp(pszStructCode, "concatenated") == 0 ) eStructCode = dsc_concatenated;
134 
135             DDF_data_type_code eTypeCode = dtc_char_string;
136             const char* pszTypeCode = CPLGetXMLValue(psIter, "dataTypeCode", "");
137             if( strcmp(pszTypeCode, "char_string") == 0 ) eTypeCode = dtc_char_string;
138             else if( strcmp(pszTypeCode, "implicit_point") == 0 ) eTypeCode = dtc_implicit_point;
139             else if( strcmp(pszTypeCode, "explicit_point") == 0 ) eTypeCode = dtc_explicit_point;
140             else if( strcmp(pszTypeCode, "explicit_point_scaled") == 0 ) eTypeCode = dtc_explicit_point_scaled;
141             else if( strcmp(pszTypeCode, "char_bit_string") == 0 ) eTypeCode = dtc_char_bit_string;
142             else if( strcmp(pszTypeCode, "bit_string") == 0 ) eTypeCode = dtc_bit_string;
143             else if( strcmp(pszTypeCode, "mixed_data_type") == 0 ) eTypeCode = dtc_mixed_data_type;
144 
145             const char* pszFormatControls = CPLGetXMLValue(psIter, "formatControls", NULL);
146             if( eStructCode != dsc_elementary )
147                 pszFormatControls = NULL;
148 
149             const char* pszArrayDescr = CPLGetXMLValue(psIter, "arrayDescr", "");
150             if( eStructCode == dsc_vector )
151                 pszArrayDescr = "";
152             else if( eStructCode == dsc_array )
153                 pszArrayDescr = "*";
154 
155             poFDefn->Create( CPLGetXMLValue(psIter, "tag", ""),
156                              CPLGetXMLValue(psIter, "fieldName", ""),
157                              pszArrayDescr,
158                              eStructCode, eTypeCode,
159                              pszFormatControls );
160 
161             CPLXMLNode* psSubIter = psIter->psChild;
162             while( psSubIter != NULL )
163             {
164                 if( psSubIter->eType == CXT_Element &&
165                     strcmp(psSubIter->pszValue, "DDFSubfieldDefn") == 0 )
166                 {
167                     poFDefn->AddSubfield( CPLGetXMLValue(psSubIter, "name", ""),
168                                           CPLGetXMLValue(psSubIter, "format", "") );
169                 }
170                 psSubIter = psSubIter->psNext;
171             }
172 
173             oModule.AddField( poFDefn );
174         }
175         else if( psIter->eType == CXT_Element &&
176                  strcmp(psIter->pszValue, "DDFRecord") == 0 )
177         {
178             if( !bCreated )
179             {
180                 oModule.Create( pszOutFilename );
181                 bCreated = TRUE;
182             }
183 
184             DDFRecord *poRec = new DDFRecord( &oModule );
185             std::map<std::string, int> oMapField;
186 
187             CPLXMLNode* psSubIter = psIter->psChild;
188             while( psSubIter != NULL )
189             {
190                 if( psSubIter->eType == CXT_Element &&
191                     strcmp(psSubIter->pszValue, "DDFField") == 0 )
192                 {
193                     DDFField *poField;
194                     const char* pszFieldName = CPLGetXMLValue(psSubIter, "name", "");
195                     DDFFieldDefn* poFieldDefn = oModule.FindFieldDefn( pszFieldName );
196                     if( poFieldDefn == NULL )
197                     {
198                         fprintf(stderr, "Can't find field '%s'\n", pszFieldName );
199                         exit(1);
200                     }
201 
202                     int nFieldOcc = oMapField[pszFieldName];
203                     oMapField[pszFieldName] ++ ;
204 
205                     poField = poRec->AddField( poFieldDefn );
206                     const char* pszValue = CPLGetXMLValue(psSubIter, "value", NULL);
207                     if( pszValue != NULL && strncmp(pszValue, "0x", 2) == 0 )
208                     {
209                         pszValue += 2;
210                         int nDataLen = (int)strlen(pszValue)  / 2;
211                         char* pabyData = (char*) malloc(nDataLen);
212                         for(int i=0;i<nDataLen;i++)
213                         {
214                             char c;
215                             int nHigh, nLow;
216                             c = pszValue[2*i];
217                             if( c >= 'A' && c <= 'F' )
218                                 nHigh = 10 + c - 'A';
219                             else
220                                 nHigh = c - '0';
221                             c = pszValue[2*i + 1];
222                             if( c >= 'A' && c <= 'F' )
223                                 nLow = 10 + c - 'A';
224                             else
225                                 nLow = c - '0';
226                             pabyData[i] = (nHigh << 4) + nLow;
227                         }
228                         poRec->SetFieldRaw( poField, nFieldOcc, (const char *) pabyData, nDataLen );
229                         free(pabyData);
230                     }
231                     else
232                     {
233                         CPLXMLNode* psSubfieldIter = psSubIter->psChild;
234                         std::map<std::string, int> oMapSubfield;
235                         while( psSubfieldIter != NULL )
236                         {
237                             if( psSubfieldIter->eType == CXT_Element &&
238                                 strcmp(psSubfieldIter->pszValue, "DDFSubfield") == 0 )
239                             {
240                                 const char* pszSubfieldName = CPLGetXMLValue(psSubfieldIter, "name", "");
241                                 const char* pszSubfieldType = CPLGetXMLValue(psSubfieldIter, "type", "");
242                                 const char* pszSubfieldValue = CPLGetXMLValue(psSubfieldIter, NULL, "");
243                                 int nOcc = oMapSubfield[pszSubfieldName];
244                                 oMapSubfield[pszSubfieldName] ++ ;
245                                 if( strcmp(pszSubfieldType, "float") == 0 )
246                                 {
247                                     poRec->SetFloatSubfield( pszFieldName, nFieldOcc, pszSubfieldName, nOcc,
248                                                            CPLAtof(pszSubfieldValue) );
249                                 }
250                                 else if( strcmp(pszSubfieldType, "integer") == 0 )
251                                 {
252                                     poRec->SetIntSubfield( pszFieldName, nFieldOcc, pszSubfieldName, nOcc,
253                                                            atoi(pszSubfieldValue) );
254                                 }
255                                 else if( strcmp(pszSubfieldType, "string") == 0 )
256                                 {
257                                     poRec->SetStringSubfield( pszFieldName, nFieldOcc, pszSubfieldName, nOcc,
258                                                               pszSubfieldValue );
259                                 }
260                                 else if( strcmp(pszSubfieldType, "binary") == 0 &&
261                                          strncmp(pszSubfieldValue, "0x", 2) == 0 )
262                                 {
263                                     pszSubfieldValue += 2;
264                                     int nDataLen = (int)strlen(pszSubfieldValue) / 2;
265                                     char* pabyData = (char*) malloc(nDataLen);
266                                     for(int i=0;i<nDataLen;i++)
267                                     {
268                                         char c;
269                                         int nHigh, nLow;
270                                         c = pszSubfieldValue[2*i];
271                                         if( c >= 'A' && c <= 'F' )
272                                             nHigh = 10 + c - 'A';
273                                         else
274                                             nHigh = c - '0';
275                                         c = pszSubfieldValue[2*i + 1];
276                                         if( c >= 'A' && c <= 'F' )
277                                             nLow = 10 + c - 'A';
278                                         else
279                                             nLow = c - '0';
280                                         pabyData[i] = (nHigh << 4) + nLow;
281                                     }
282                                     poRec->SetStringSubfield( pszFieldName, nFieldOcc, pszSubfieldName, nOcc,
283                                                               pabyData, nDataLen );
284                                     free(pabyData);
285                                 }
286                             }
287                             psSubfieldIter = psSubfieldIter->psNext;
288                         }
289                     }
290                 }
291                 psSubIter = psSubIter->psNext;
292             }
293 
294             poRec->Write();
295             delete poRec;
296         }
297 
298         psIter = psIter->psNext;
299     }
300 
301     CPLDestroyXMLNode(poRoot);
302 
303     oModule.Close();
304 
305     return 0;
306 }
307