Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: NITF Read/Write Library
4 : * Purpose: Module responsible for implementation of DE segments.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2010-2011, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdal.h"
14 : #include "nitflib.h"
15 : #include "cpl_vsi.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_string.h"
18 :
19 : #ifndef CPL_IGNORE_RET_VAL_INT_defined
20 : #define CPL_IGNORE_RET_VAL_INT_defined
21 :
22 0 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
23 : {
24 0 : }
25 : #endif
26 :
27 : /************************************************************************/
28 : /* NITFDESAccess() */
29 : /************************************************************************/
30 :
31 15 : NITFDES *NITFDESAccess(NITFFile *psFile, int iSegment)
32 :
33 : {
34 : NITFDES *psDES;
35 : char *pachHeader;
36 : NITFSegmentInfo *psSegInfo;
37 : char szDESID[26];
38 : int nOffset;
39 : int bHasDESOFLW;
40 : int nDESSHL;
41 :
42 : /* -------------------------------------------------------------------- */
43 : /* Verify segment, and return existing DES accessor if there */
44 : /* is one. */
45 : /* -------------------------------------------------------------------- */
46 15 : if (iSegment < 0 || iSegment >= psFile->nSegmentCount)
47 0 : return NULL;
48 :
49 15 : psSegInfo = psFile->pasSegmentInfo + iSegment;
50 :
51 15 : if (!EQUAL(psSegInfo->szSegmentType, "DE"))
52 0 : return NULL;
53 :
54 15 : if (psSegInfo->hAccess != NULL)
55 0 : return (NITFDES *)psSegInfo->hAccess;
56 :
57 : /* -------------------------------------------------------------------- */
58 : /* Read the DES subheader. */
59 : /* -------------------------------------------------------------------- */
60 15 : if (psSegInfo->nSegmentHeaderSize < 200)
61 : {
62 0 : CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
63 0 : return NULL;
64 : }
65 :
66 15 : pachHeader = (char *)VSI_MALLOC_VERBOSE(psSegInfo->nSegmentHeaderSize);
67 15 : if (pachHeader == NULL)
68 : {
69 0 : return NULL;
70 : }
71 :
72 15 : retry:
73 15 : if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentHeaderStart, SEEK_SET) != 0 ||
74 15 : VSIFReadL(pachHeader, 1, psSegInfo->nSegmentHeaderSize, psFile->fp) !=
75 15 : psSegInfo->nSegmentHeaderSize)
76 : {
77 0 : CPLError(CE_Failure, CPLE_FileIO,
78 : "Failed to read %u byte DES subheader from " CPL_FRMT_GUIB ".",
79 : psSegInfo->nSegmentHeaderSize, psSegInfo->nSegmentHeaderStart);
80 0 : CPLFree(pachHeader);
81 0 : return NULL;
82 : }
83 :
84 15 : if (!STARTS_WITH_CI(pachHeader, "DE"))
85 : {
86 0 : if (STARTS_WITH_CI(pachHeader + 4, "DERegistered"))
87 : {
88 : /* BAO_46_Ed1/rpf/conc/concz10/000fz010.ona and cie are buggy */
89 0 : CPLDebug("NITF",
90 : "Patching nSegmentHeaderStart and nSegmentStart for DE "
91 : "segment %d",
92 : iSegment);
93 0 : psSegInfo->nSegmentHeaderStart += 4;
94 0 : psSegInfo->nSegmentStart += 4;
95 0 : goto retry;
96 : }
97 :
98 0 : CPLError(CE_Failure, CPLE_AppDefined,
99 : "Invalid segment prefix for DE segment %d", iSegment);
100 :
101 0 : CPLFree(pachHeader);
102 0 : return NULL;
103 : }
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Initialize DES object. */
107 : /* -------------------------------------------------------------------- */
108 15 : psDES = (NITFDES *)CPLCalloc(sizeof(NITFDES), 1);
109 :
110 15 : psDES->psFile = psFile;
111 15 : psDES->iSegment = iSegment;
112 15 : psDES->pachHeader = pachHeader;
113 :
114 15 : psSegInfo->hAccess = psDES;
115 :
116 : /* -------------------------------------------------------------------- */
117 : /* Collect a variety of information as metadata. */
118 : /* -------------------------------------------------------------------- */
119 : #define GetMD(length, name) \
120 : do \
121 : { \
122 : NITFExtractMetadata(&(psDES->papszMetadata), pachHeader, nOffset, \
123 : length, #name); \
124 : nOffset += length; \
125 : } while (0)
126 :
127 15 : nOffset = 2;
128 15 : GetMD(25, DESID);
129 15 : GetMD(2, DESVER);
130 15 : GetMD(1, DECLAS);
131 15 : GetMD(2, DESCLSY);
132 15 : GetMD(11, DESCODE);
133 15 : GetMD(2, DESCTLH);
134 15 : GetMD(20, DESREL);
135 15 : GetMD(2, DESDCTP);
136 15 : GetMD(8, DESDCDT);
137 15 : GetMD(4, DESDCXM);
138 15 : GetMD(1, DESDG);
139 15 : GetMD(8, DESDGDT);
140 15 : GetMD(43, DESCLTX);
141 15 : GetMD(1, DESCATP);
142 15 : GetMD(40, DESCAUT);
143 15 : GetMD(1, DESCRSN);
144 15 : GetMD(8, DESSRDT);
145 15 : GetMD(15, DESCTLN);
146 :
147 : /* Load DESID */
148 15 : NITFGetField(szDESID, pachHeader, 2, 25);
149 :
150 : /* For NITF < 02.10, we cannot rely on DESID=TRE_OVERFLOW to detect */
151 : /* if DESOFLW and DESITEM are present. So if the next 4 bytes are non */
152 : /* numeric, we'll assume that DESOFLW is there */
153 15 : bHasDESOFLW =
154 27 : STARTS_WITH_CI(szDESID, "TRE_OVERFLOW") ||
155 12 : (!((pachHeader[nOffset + 0] >= '0' && pachHeader[nOffset + 0] <= '9') &&
156 12 : (pachHeader[nOffset + 1] >= '0' && pachHeader[nOffset + 1] <= '9') &&
157 12 : (pachHeader[nOffset + 2] >= '0' && pachHeader[nOffset + 2] <= '9') &&
158 12 : (pachHeader[nOffset + 3] >= '0' && pachHeader[nOffset + 3] <= '9')));
159 :
160 15 : if (bHasDESOFLW)
161 : {
162 3 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 6 + 3)
163 : {
164 0 : CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
165 0 : NITFDESDeaccess(psDES);
166 0 : return NULL;
167 : }
168 3 : GetMD(6, DESOFLW);
169 3 : GetMD(3, DESITEM);
170 : }
171 :
172 15 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + 4)
173 : {
174 0 : CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
175 0 : NITFDESDeaccess(psDES);
176 0 : return NULL;
177 : }
178 :
179 15 : GetMD(4, DESSHL);
180 15 : nDESSHL = atoi(CSLFetchNameValue(psDES->papszMetadata, "DESSHL"));
181 :
182 15 : if (nDESSHL < 0)
183 : {
184 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for DESSHL");
185 0 : NITFDESDeaccess(psDES);
186 0 : return NULL;
187 : }
188 15 : if ((int)psSegInfo->nSegmentHeaderSize < nOffset + nDESSHL)
189 : {
190 0 : CPLError(CE_Failure, CPLE_AppDefined, "DES header too small");
191 0 : NITFDESDeaccess(psDES);
192 0 : return NULL;
193 : }
194 :
195 15 : if (nDESSHL > 0)
196 10 : GetMD(nDESSHL, DESSHF);
197 :
198 15 : if ((int)psSegInfo->nSegmentHeaderSize > nOffset)
199 : {
200 0 : char *pszEscapedDESDATA = CPLEscapeString(
201 0 : pachHeader + nOffset, (int)psSegInfo->nSegmentHeaderSize - nOffset,
202 : CPLES_BackslashQuotable);
203 0 : psDES->papszMetadata =
204 0 : CSLSetNameValue(psDES->papszMetadata, "DESDATA", pszEscapedDESDATA);
205 0 : CPLFree(pszEscapedDESDATA);
206 : }
207 : else
208 : {
209 :
210 : #define TEN_MEGABYTES 10485760
211 :
212 15 : if (psSegInfo->nSegmentSize > TEN_MEGABYTES)
213 : {
214 0 : const char *pszOffset = CPLSPrintf(
215 0 : CPL_FRMT_GUIB, psFile->pasSegmentInfo[iSegment].nSegmentStart);
216 0 : const char *pszSize = CPLSPrintf(
217 0 : CPL_FRMT_GUIB, psFile->pasSegmentInfo[iSegment].nSegmentSize);
218 :
219 0 : psDES->papszMetadata = CSLSetNameValue(psDES->papszMetadata,
220 : "DESDATA_OFFSET", pszOffset);
221 0 : psDES->papszMetadata = CSLSetNameValue(psDES->papszMetadata,
222 : "DESDATA_LENGTH", pszSize);
223 : }
224 : else
225 : {
226 : char *pachData =
227 15 : (char *)VSI_MALLOC_VERBOSE((size_t)psSegInfo->nSegmentSize);
228 15 : if (pachData == NULL)
229 : {
230 : /* nothing */
231 : }
232 15 : else if (VSIFSeekL(psFile->fp, psSegInfo->nSegmentStart,
233 15 : SEEK_SET) != 0 ||
234 15 : VSIFReadL(pachData, 1, (size_t)psSegInfo->nSegmentSize,
235 15 : psFile->fp) != psSegInfo->nSegmentSize)
236 : {
237 0 : CPLDebug("NITF",
238 : "Failed to read " CPL_FRMT_GUIB
239 : " bytes DES data from " CPL_FRMT_GUIB ".",
240 : psSegInfo->nSegmentSize, psSegInfo->nSegmentStart);
241 : }
242 : else
243 : {
244 : char *pszEscapedDESDATA =
245 15 : CPLEscapeString(pachData, (int)psSegInfo->nSegmentSize,
246 : CPLES_BackslashQuotable);
247 15 : psDES->papszMetadata = CSLSetNameValue(
248 : psDES->papszMetadata, "DESDATA", pszEscapedDESDATA);
249 15 : CPLFree(pszEscapedDESDATA);
250 : }
251 15 : CPLFree(pachData);
252 : }
253 :
254 : #ifdef notdef
255 : /* Disabled because might generate a huge amount of elements */
256 : if (STARTS_WITH_CI(szDESID, "CSATTA DES"))
257 : {
258 : int nNumAtt = atoi(
259 : CSLFetchNameValueDef(psDES->papszMetadata, "NUM_ATT", "0"));
260 : if (nNumAtt * 8 * 4 == psSegInfo->nSegmentSize)
261 : {
262 : int nMDSize = CSLCount(psDES->papszMetadata);
263 : char **papszMD = (char **)VSIRealloc(
264 : psDES->papszMetadata,
265 : (nMDSize + nNumAtt * 4 + 1) * sizeof(char *));
266 : if (papszMD)
267 : {
268 : int i, j;
269 : const GByte *pachDataIter = pachData;
270 :
271 : psDES->papszMetadata = papszMD;
272 : for (i = 0; i < nNumAtt; i++)
273 : {
274 : char szAttrNameValue[64 + 1 + 256 + 1];
275 : double dfVal;
276 : for (j = 0; j < 4; j++)
277 : {
278 : memcpy(&dfVal, pachDataIter, 8);
279 : CPL_MSBPTR64(&dfVal);
280 : pachDataIter += 8;
281 : CPLsprintf(szAttrNameValue, "ATT_Q%d_%d=%.16g",
282 : j + 1, i, dfVal);
283 : papszMD[nMDSize + i * 4 + j] =
284 : CPLStrdup(szAttrNameValue);
285 : }
286 : }
287 : papszMD[nMDSize + nNumAtt * 4] = NULL;
288 : }
289 : }
290 : }
291 : #endif
292 : }
293 :
294 15 : return psDES;
295 : }
296 :
297 : /************************************************************************/
298 : /* NITFDESDeaccess() */
299 : /************************************************************************/
300 :
301 15 : void NITFDESDeaccess(NITFDES *psDES)
302 :
303 : {
304 15 : CPLAssert(psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess == psDES);
305 :
306 15 : psDES->psFile->pasSegmentInfo[psDES->iSegment].hAccess = NULL;
307 :
308 15 : CPLFree(psDES->pachHeader);
309 15 : CSLDestroy(psDES->papszMetadata);
310 :
311 15 : CPLFree(psDES);
312 15 : }
313 :
314 : /************************************************************************/
315 : /* NITFDESGetTRE() */
316 : /************************************************************************/
317 :
318 : /**
319 : * Return the TRE located at nOffset.
320 : *
321 : * @param psDES descriptor of the DE segment
322 : * @param nOffset offset of the TRE relative to the beginning of the
323 : * segment data
324 : * @param szTREName will be filled with the TRE name
325 : * @param ppabyTREData will be allocated by the function and filled with the
326 : * TRE content (in raw form)
327 : * @param pnFoundTRESize will be filled with the TRE size (excluding the first
328 : * 11 bytes)
329 : * @return TRUE if a TRE was found
330 : */
331 :
332 9 : int NITFDESGetTRE(NITFDES *psDES, int nOffset, char szTREName[7],
333 : char **ppabyTREData, int *pnFoundTRESize)
334 : {
335 : char szTREHeader[12];
336 : char szTRETempName[7];
337 : NITFSegmentInfo *psSegInfo;
338 : VSILFILE *fp;
339 : int nTRESize;
340 :
341 9 : memset(szTREName, '\0', 7);
342 9 : if (ppabyTREData)
343 9 : *ppabyTREData = NULL;
344 9 : if (pnFoundTRESize)
345 9 : *pnFoundTRESize = 0;
346 :
347 9 : if (nOffset < 0)
348 0 : return FALSE;
349 :
350 9 : if (psDES == NULL)
351 0 : return FALSE;
352 :
353 9 : if (CSLFetchNameValue(psDES->papszMetadata, "DESOFLW") == NULL)
354 2 : return FALSE;
355 :
356 7 : psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
357 7 : fp = psDES->psFile->fp;
358 :
359 7 : if ((size_t)nOffset >= psSegInfo->nSegmentSize)
360 2 : return FALSE;
361 :
362 10 : if (VSIFSeekL(fp, psSegInfo->nSegmentStart + nOffset, SEEK_SET) != 0 ||
363 5 : VSIFReadL(szTREHeader, 1, 11, fp) != 11)
364 : {
365 : /* Some files have a nSegmentSize larger than what it is in reality */
366 : /* So exit silently if we're at end of file */
367 0 : if (VSIFSeekL(fp, 0, SEEK_END) != 0 ||
368 0 : VSIFTellL(fp) == psSegInfo->nSegmentStart + nOffset)
369 0 : return FALSE;
370 :
371 0 : CPLError(CE_Failure, CPLE_FileIO,
372 : "Cannot get 11 bytes at offset " CPL_FRMT_GUIB ".",
373 0 : psSegInfo->nSegmentStart + nOffset);
374 0 : return FALSE;
375 : }
376 5 : szTREHeader[11] = '\0';
377 :
378 5 : memcpy(szTRETempName, szTREHeader, 6);
379 5 : szTRETempName[6] = '\0';
380 :
381 5 : nTRESize = atoi(szTREHeader + 6);
382 5 : if (nTRESize < 0)
383 : {
384 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid size (%d) for TRE %s",
385 : nTRESize, szTRETempName);
386 0 : return FALSE;
387 : }
388 5 : if ((size_t)(nOffset + 11 + nTRESize) > psSegInfo->nSegmentSize)
389 : {
390 0 : CPLError(
391 : CE_Failure, CPLE_AppDefined,
392 : "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
393 0 : szTRETempName, (int)(psSegInfo->nSegmentSize - (nOffset + 11)),
394 : nTRESize);
395 0 : return FALSE;
396 : }
397 :
398 5 : if (ppabyTREData)
399 : {
400 : /* Allocate one extra byte for the NULL terminating character */
401 5 : *ppabyTREData = (char *)VSI_MALLOC_VERBOSE(nTRESize + 1);
402 5 : if (*ppabyTREData == NULL)
403 : {
404 0 : return FALSE;
405 : }
406 5 : (*ppabyTREData)[nTRESize] = '\0';
407 :
408 5 : if ((int)VSIFReadL(*ppabyTREData, 1, nTRESize, fp) != nTRESize)
409 : {
410 0 : CPLError(CE_Failure, CPLE_FileIO,
411 : "Cannot get %d bytes at offset " CPL_FRMT_GUIB ".",
412 : nTRESize, VSIFTellL(fp));
413 0 : VSIFree(*ppabyTREData);
414 0 : *ppabyTREData = NULL;
415 0 : return FALSE;
416 : }
417 : }
418 :
419 5 : strcpy(szTREName, szTRETempName);
420 5 : if (pnFoundTRESize)
421 5 : *pnFoundTRESize = nTRESize;
422 :
423 5 : return TRUE;
424 : }
425 :
426 : /************************************************************************/
427 : /* NITFDESFreeTREData() */
428 : /************************************************************************/
429 :
430 5 : void NITFDESFreeTREData(char *pabyTREData)
431 : {
432 5 : VSIFree(pabyTREData);
433 5 : }
434 :
435 : /************************************************************************/
436 : /* NITFDESExtractShapefile() */
437 : /************************************************************************/
438 :
439 0 : int NITFDESExtractShapefile(NITFDES *psDES, const char *pszRadixFileName)
440 : {
441 : NITFSegmentInfo *psSegInfo;
442 0 : const char *apszExt[3] = {NULL};
443 0 : int anOffset[4] = {0};
444 : int iShpFile;
445 : char *pszFilename;
446 : size_t nFilenameLen;
447 0 : char *pachHeader = psDES->pachHeader;
448 :
449 0 : int nDESSHL = atoi(CSLFetchNameValue(psDES->papszMetadata, "DESSHL"));
450 0 : if (nDESSHL != 62 && nDESSHL != 80)
451 : {
452 0 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid DESSHL for CSSHPA DES");
453 0 : return FALSE;
454 : }
455 :
456 0 : char **papszMetadataBackup = CSLDuplicate(psDES->papszMetadata);
457 0 : psDES->papszMetadata = NULL;
458 0 : int nOffset = 200 + 25 + 10;
459 0 : if (nDESSHL == 80)
460 0 : nOffset += 18;
461 0 : GetMD(3, SHAPE1_NAME);
462 0 : GetMD(6, SHAPE1_START);
463 0 : GetMD(3, SHAPE2_NAME);
464 0 : GetMD(6, SHAPE2_START);
465 0 : GetMD(3, SHAPE3_NAME);
466 0 : GetMD(6, SHAPE3_START);
467 :
468 0 : psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
469 :
470 0 : apszExt[0] = CSLFetchNameValue(psDES->papszMetadata, "SHAPE1_NAME");
471 0 : anOffset[0] = atoi(CSLFetchNameValue(psDES->papszMetadata, "SHAPE1_START"));
472 0 : apszExt[1] = CSLFetchNameValue(psDES->papszMetadata, "SHAPE2_NAME");
473 0 : anOffset[1] = atoi(CSLFetchNameValue(psDES->papszMetadata, "SHAPE2_START"));
474 0 : apszExt[2] = CSLFetchNameValue(psDES->papszMetadata, "SHAPE3_NAME");
475 0 : anOffset[2] = atoi(CSLFetchNameValue(psDES->papszMetadata, "SHAPE3_START"));
476 0 : anOffset[3] = (int)psSegInfo->nSegmentSize;
477 :
478 0 : int ret = FALSE;
479 0 : for (iShpFile = 0; iShpFile < 3; iShpFile++)
480 : {
481 0 : if (!EQUAL(apszExt[iShpFile], "SHP") &&
482 0 : !EQUAL(apszExt[iShpFile], "SHX") &&
483 0 : !EQUAL(apszExt[iShpFile], "DBF"))
484 0 : goto end;
485 :
486 0 : if (anOffset[iShpFile] < 0 ||
487 0 : anOffset[iShpFile] >= anOffset[iShpFile + 1])
488 0 : goto end;
489 : }
490 :
491 0 : nFilenameLen = strlen(pszRadixFileName) + 4 + 1;
492 0 : pszFilename = (char *)VSI_MALLOC_VERBOSE(nFilenameLen);
493 0 : if (pszFilename == NULL)
494 0 : goto end;
495 :
496 0 : for (iShpFile = 0; iShpFile < 3; iShpFile++)
497 : {
498 : VSILFILE *fp;
499 : GByte *pabyBuffer;
500 0 : int nSize = anOffset[iShpFile + 1] - anOffset[iShpFile];
501 :
502 0 : pabyBuffer = (GByte *)VSI_MALLOC_VERBOSE(nSize);
503 0 : if (pabyBuffer == NULL)
504 : {
505 0 : VSIFree(pszFilename);
506 0 : goto end;
507 : }
508 :
509 0 : if (VSIFSeekL(psDES->psFile->fp,
510 0 : psSegInfo->nSegmentStart + anOffset[iShpFile],
511 0 : SEEK_SET) != 0 ||
512 0 : VSIFReadL(pabyBuffer, 1, nSize, psDES->psFile->fp) != (size_t)nSize)
513 : {
514 0 : VSIFree(pabyBuffer);
515 0 : VSIFree(pszFilename);
516 0 : goto end;
517 : }
518 :
519 0 : snprintf(pszFilename, nFilenameLen, "%s.%s", pszRadixFileName,
520 : apszExt[iShpFile]);
521 0 : fp = VSIFOpenL(pszFilename, "wb");
522 0 : if (fp == NULL)
523 : {
524 0 : VSIFree(pabyBuffer);
525 0 : VSIFree(pszFilename);
526 0 : goto end;
527 : }
528 :
529 0 : if ((int)VSIFWriteL(pabyBuffer, 1, nSize, fp) != nSize)
530 : {
531 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
532 0 : VSIFree(pabyBuffer);
533 0 : VSIFree(pszFilename);
534 0 : goto end;
535 : }
536 0 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
537 0 : VSIFree(pabyBuffer);
538 : }
539 :
540 0 : VSIFree(pszFilename);
541 :
542 0 : ret = TRUE;
543 0 : end:
544 0 : CSLDestroy(psDES->papszMetadata);
545 0 : psDES->papszMetadata = papszMetadataBackup;
546 0 : return ret;
547 : }
548 :
549 : /************************************************************************/
550 : /* NITFDESGetXml() */
551 : /************************************************************************/
552 :
553 11 : CPLXMLNode *NITFDESGetXml(NITFFile *psFile, int iSegment, bool bValidate,
554 : bool *pbGotError)
555 : {
556 : CPLXMLNode *psDesNode;
557 : char **papszTmp;
558 11 : NITFDES *psDes = NITFDESAccess(psFile, iSegment);
559 :
560 11 : if (psDes == NULL)
561 : {
562 0 : return NULL;
563 : }
564 :
565 11 : if (psDes->papszMetadata == NULL)
566 : {
567 0 : NITFDESDeaccess(psDes);
568 0 : return NULL;
569 : }
570 :
571 11 : psDesNode = CPLCreateXMLNode(NULL, CXT_Element, "des");
572 11 : papszTmp = psDes->papszMetadata;
573 :
574 11 : bool bIsXML_DATA_CONTENT = false;
575 241 : while (papszTmp != NULL && *papszTmp != NULL)
576 : {
577 : CPLXMLNode *psFieldNode;
578 : CPLXMLNode *psNameNode;
579 :
580 : const char *pszMDval;
581 : const char *pszMDsep;
582 :
583 230 : if ((pszMDsep = strchr(*papszTmp, '=')) == NULL)
584 : {
585 0 : NITFDESDeaccess(psDes);
586 0 : CPLDestroyXMLNode(psDesNode);
587 0 : CPLError(CE_Failure, CPLE_AppDefined,
588 : "NITF DES metadata item missing separator");
589 0 : return NULL;
590 : }
591 :
592 230 : pszMDval = pszMDsep + 1;
593 :
594 230 : if (papszTmp == psDes->papszMetadata)
595 : {
596 11 : bIsXML_DATA_CONTENT = strcmp(pszMDval, "XML_DATA_CONTENT") == 0;
597 11 : CPLCreateXMLNode(CPLCreateXMLNode(psDesNode, CXT_Attribute, "name"),
598 : CXT_Text, pszMDval);
599 : }
600 : else
601 : {
602 219 : char *pszMDname = (char *)CPLMalloc(pszMDsep - *papszTmp + 1);
603 219 : CPLStrlcpy(pszMDname, *papszTmp, pszMDsep - *papszTmp + 1);
604 :
605 219 : psFieldNode = CPLCreateXMLNode(psDesNode, CXT_Element, "field");
606 219 : psNameNode = CPLCreateXMLNode(psFieldNode, CXT_Attribute, "name");
607 219 : CPLCreateXMLNode(psNameNode, CXT_Text, pszMDname);
608 :
609 219 : if (strcmp(pszMDname, "DESSHF") == 0)
610 : {
611 8 : CPLAddXMLAttributeAndValue(psFieldNode, "value", pszMDval);
612 8 : CPLXMLNode *psChild = NITFCreateXMLDesUserDefinedSubHeader(
613 : psFile, psDes, bValidate, pbGotError);
614 8 : if (psChild)
615 : {
616 4 : CPLAddXMLChild(psFieldNode, psChild);
617 : }
618 : }
619 211 : else if (strcmp(pszMDname, "DESDATA") == 0)
620 : {
621 : int nLen;
622 : char *pszUnescaped =
623 11 : CPLUnescapeString(pszMDval, &nLen, CPLES_BackslashQuotable);
624 : char *pszBase64 =
625 11 : CPLBase64Encode(nLen, (const GByte *)pszUnescaped);
626 :
627 11 : if (pszBase64 == NULL)
628 : {
629 0 : NITFDESDeaccess(psDes);
630 0 : CPLDestroyXMLNode(psDesNode);
631 0 : CPLFree(pszMDname);
632 0 : CPLFree(pszUnescaped);
633 0 : CPLError(CE_Failure, CPLE_AppDefined,
634 : "NITF DES data could not be encoded");
635 0 : return NULL;
636 : }
637 :
638 11 : CPLXMLNode *psChild = NITFCreateXMLDesDataFields(
639 : psFile, psDes, (GByte *)pszUnescaped, nLen, bValidate,
640 : pbGotError);
641 11 : if (psChild)
642 : {
643 1 : CPLAddXMLAttributeAndValue(psFieldNode, "value", pszBase64);
644 1 : CPLAddXMLChild(psFieldNode, psChild);
645 : }
646 10 : else if (bIsXML_DATA_CONTENT)
647 : {
648 2 : CPLXMLNode *psXML = CPLParseXMLString(pszUnescaped);
649 2 : if (psXML)
650 : {
651 1 : CPLXMLNode *psXMLContent = CPLCreateXMLNode(
652 : psFieldNode, CXT_Element, "xml_content");
653 1 : CPLAddXMLChild(psXMLContent, psXML);
654 : }
655 : else
656 : {
657 1 : CPLAddXMLAttributeAndValue(psFieldNode, "value",
658 : pszBase64);
659 : }
660 : }
661 : else
662 : {
663 8 : CPLAddXMLAttributeAndValue(psFieldNode, "value", pszBase64);
664 : }
665 :
666 11 : CPLFree(pszBase64);
667 11 : CPLFree(pszUnescaped);
668 : }
669 : else
670 : {
671 200 : CPLAddXMLAttributeAndValue(psFieldNode, "value", pszMDval);
672 : }
673 :
674 219 : CPLFree(pszMDname);
675 : }
676 :
677 230 : ++papszTmp;
678 : }
679 :
680 11 : NITFDESDeaccess(psDes);
681 :
682 11 : return psDesNode;
683 : }
684 :
685 : #undef GetMD
|