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