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