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 : }
|