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