LCOV - code coverage report
Current view: top level - frmts/nitf - rpftocfile.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 245 380 64.5 %
Date: 2024-11-21 22:18:42 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  RPF A.TOC read Library
       4             :  * Purpose:  Module responsible for opening a RPF TOC file, populating RPFToc
       5             :  *           structure
       6             :  * Author:   Even Rouault, even.rouault at spatialys.com
       7             :  *
       8             :  **********************************************************************
       9             :  * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : /* Portions of code are placed under the following copyright : */
      15             : /*
      16             :  ******************************************************************************
      17             :  * Copyright (C) 1995 Logiciels et Applications Scientifiques (L.A.S.) Inc
      18             :  * Permission to use, copy, modify and distribute this software and
      19             :  * its documentation for any purpose and without fee is hereby granted,
      20             :  * provided that the above copyright notice appear in all copies, that
      21             :  * both the copyright notice and this permission notice appear in
      22             :  * supporting documentation, and that the name of L.A.S. Inc not be used
      23             :  * in advertising or publicity pertaining to distribution of the software
      24             :  * without specific, written prior permission. L.A.S. Inc. makes no
      25             :  * representations about the suitability of this software for any purpose.
      26             :  * It is provided "as is" without express or implied warranty.
      27             :  ******************************************************************************
      28             :  */
      29             : 
      30             : #include "cpl_port.h"
      31             : #include "rpftoclib.h"
      32             : 
      33             : #include <climits>
      34             : #include <cmath>
      35             : #include <cstring>
      36             : #if HAVE_FCNTL_H
      37             : #include <fcntl.h>
      38             : #endif
      39             : 
      40             : #include "cpl_conv.h"
      41             : #include "cpl_error.h"
      42             : #include "cpl_string.h"
      43             : #include "cpl_vsi.h"
      44             : #include "nitflib.h"
      45             : 
      46             : /************************************************************************/
      47             : /*                        RPFTOCTrim()                                    */
      48             : /************************************************************************/
      49             : 
      50          50 : static void RPFTOCTrim(char *str)
      51             : {
      52          50 :     char *c = str;
      53          50 :     if (str == nullptr || *str == 0)
      54           0 :         return;
      55             : 
      56          50 :     while (*c == ' ')
      57             :     {
      58           0 :         c++;
      59             :     }
      60          50 :     if (c != str)
      61             :     {
      62           0 :         memmove(str, c, strlen(c) + 1);
      63             :     }
      64             : 
      65          50 :     int i = static_cast<int>(strlen(str)) - 1;
      66          70 :     while (i >= 0 && str[i] == ' ')
      67             :     {
      68          20 :         str[i] = 0;
      69          20 :         i--;
      70             :     }
      71             : }
      72             : 
      73             : /************************************************************************/
      74             : /*                        RPFTOCRead()                                 */
      75             : /************************************************************************/
      76             : 
      77           0 : RPFToc *RPFTOCRead(const char *pszFilename, NITFFile *psFile)
      78             : {
      79             :     int nTRESize;
      80             :     const char *pachTRE =
      81           0 :         NITFFindTRE(psFile->pachTRE, psFile->nTREBytes, "RPFHDR", &nTRESize);
      82           0 :     if (pachTRE == nullptr)
      83             :     {
      84           0 :         CPLError(CE_Failure, CPLE_NotSupported,
      85             :                  "Invalid TOC file. Can't find RPFHDR.");
      86           0 :         return nullptr;
      87             :     }
      88             : 
      89           0 :     if (nTRESize != 48)
      90             :     {
      91           0 :         CPLError(CE_Failure, CPLE_NotSupported, "RPFHDR TRE wrong size.");
      92           0 :         return nullptr;
      93             :     }
      94             : 
      95           0 :     return RPFTOCReadFromBuffer(pszFilename, psFile->fp, pachTRE);
      96             : }
      97             : 
      98             : /* This function is directly inspired by function parse_toc coming from
      99             :  * ogdi/driver/rpf/utils.c */
     100             : 
     101          10 : RPFToc *RPFTOCReadFromBuffer(const char *pszFilename, VSILFILE *fp,
     102             :                              const char *tocHeader)
     103             : {
     104          10 :     tocHeader += 1;  /* skip endian */
     105          10 :     tocHeader += 2;  /* skip header length */
     106          10 :     tocHeader += 12; /* skip file name : this should be A.TOC (padded) */
     107          10 :     tocHeader += 1;  /* skip new  */
     108          10 :     tocHeader += 15; /* skip standard_num  */
     109          10 :     tocHeader += 8;  /* skip standard_date  */
     110          10 :     tocHeader += 1;  /* skip classification  */
     111          10 :     tocHeader += 2;  /* skip country  */
     112          10 :     tocHeader += 2;  /* skip release  */
     113             : 
     114             :     unsigned int locationSectionPhysicalLocation;
     115          10 :     memcpy(&locationSectionPhysicalLocation, tocHeader, sizeof(unsigned int));
     116          10 :     CPL_MSBPTR32(&locationSectionPhysicalLocation);
     117             : 
     118          10 :     if (VSIFSeekL(fp, locationSectionPhysicalLocation, SEEK_SET) != 0)
     119             :     {
     120           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     121             :                  "Invalid TOC file. Unable to seek to "
     122             :                  "locationSectionPhysicalLocation at offset %d.",
     123             :                  locationSectionPhysicalLocation);
     124           0 :         return nullptr;
     125             :     }
     126             : 
     127             :     int nSections;
     128          10 :     NITFLocation *pasLocations = NITFReadRPFLocationTable(fp, &nSections);
     129             : 
     130          10 :     unsigned int boundaryRectangleSectionSubHeaderPhysIndex = 0;
     131          10 :     unsigned int boundaryRectangleTablePhysIndex = 0;
     132          10 :     unsigned int frameFileIndexSectionSubHeaderPhysIndex = 0;
     133          10 :     unsigned int frameFileIndexSubsectionPhysIndex = 0;
     134             : 
     135          50 :     for (int i = 0; i < nSections; i++)
     136             :     {
     137          40 :         if (pasLocations[i].nLocId == LID_BoundaryRectangleSectionSubheader)
     138             :         {
     139          10 :             boundaryRectangleSectionSubHeaderPhysIndex =
     140          10 :                 pasLocations[i].nLocOffset;
     141             :         }
     142          30 :         else if (pasLocations[i].nLocId == LID_BoundaryRectangleTable)
     143             :         {
     144          10 :             boundaryRectangleTablePhysIndex = pasLocations[i].nLocOffset;
     145             :         }
     146          20 :         else if (pasLocations[i].nLocId == LID_FrameFileIndexSectionSubHeader)
     147             :         {
     148          10 :             frameFileIndexSectionSubHeaderPhysIndex =
     149          10 :                 pasLocations[i].nLocOffset;
     150             :         }
     151          10 :         else if (pasLocations[i].nLocId == LID_FrameFileIndexSubsection)
     152             :         {
     153          10 :             frameFileIndexSubsectionPhysIndex = pasLocations[i].nLocOffset;
     154             :         }
     155             :     }
     156             : 
     157          10 :     CPLFree(pasLocations);
     158             : 
     159          10 :     if (boundaryRectangleSectionSubHeaderPhysIndex == 0)
     160             :     {
     161           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     162             :                  "Invalid TOC file. Can't find "
     163             :                  "LID_BoundaryRectangleSectionSubheader.");
     164           0 :         return nullptr;
     165             :     }
     166          10 :     if (boundaryRectangleTablePhysIndex == 0)
     167             :     {
     168           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     169             :                  "Invalid TOC file. Can't find LID_BoundaryRectangleTable.");
     170           0 :         return nullptr;
     171             :     }
     172          10 :     if (frameFileIndexSectionSubHeaderPhysIndex == 0)
     173             :     {
     174           0 :         CPLError(
     175             :             CE_Failure, CPLE_NotSupported,
     176             :             "Invalid TOC file. Can't find LID_FrameFileIndexSectionSubHeader.");
     177           0 :         return nullptr;
     178             :     }
     179          10 :     if (frameFileIndexSubsectionPhysIndex == 0)
     180             :     {
     181           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     182             :                  "Invalid TOC file. Can't find LID_FrameFileIndexSubsection.");
     183           0 :         return nullptr;
     184             :     }
     185             : 
     186          10 :     if (VSIFSeekL(fp, boundaryRectangleSectionSubHeaderPhysIndex, SEEK_SET) !=
     187             :         0)
     188             :     {
     189           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     190             :                  "Invalid TOC file. Unable to seek to "
     191             :                  "boundaryRectangleSectionSubHeaderPhysIndex at offset %d.",
     192             :                  boundaryRectangleSectionSubHeaderPhysIndex);
     193           0 :         return nullptr;
     194             :     }
     195             : 
     196             :     unsigned int boundaryRectangleTableOffset;
     197          10 :     bool bOK = VSIFReadL(&boundaryRectangleTableOffset,
     198          10 :                          sizeof(boundaryRectangleTableOffset), 1, fp) == 1;
     199          10 :     CPL_MSBPTR32(&boundaryRectangleTableOffset);
     200             : 
     201             :     unsigned short boundaryRectangleCount;
     202          10 :     bOK &= VSIFReadL(&boundaryRectangleCount, sizeof(boundaryRectangleCount), 1,
     203          10 :                      fp) == 1;
     204          10 :     CPL_MSBPTR16(&boundaryRectangleCount);
     205             : 
     206          10 :     if (!bOK || VSIFSeekL(fp, boundaryRectangleTablePhysIndex, SEEK_SET) != 0)
     207             :     {
     208           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     209             :                  "Invalid TOC file. Unable to seek to "
     210             :                  "boundaryRectangleTablePhysIndex at offset %d.",
     211             :                  boundaryRectangleTablePhysIndex);
     212           0 :         return nullptr;
     213             :     }
     214             : 
     215          10 :     RPFToc *toc = reinterpret_cast<RPFToc *>(CPLMalloc(sizeof(RPFToc)));
     216          10 :     toc->nEntries = boundaryRectangleCount;
     217          10 :     toc->entries = reinterpret_cast<RPFTocEntry *>(
     218          10 :         CPLMalloc(boundaryRectangleCount * sizeof(RPFTocEntry)));
     219          10 :     memset(toc->entries, 0, boundaryRectangleCount * sizeof(RPFTocEntry));
     220             : 
     221          20 :     for (int i = 0; i < toc->nEntries; i++)
     222             :     {
     223          10 :         toc->entries[i].isOverviewOrLegend = 0;
     224             : 
     225          10 :         bOK &= VSIFReadL(toc->entries[i].type, 1, 5, fp) == 5;
     226          10 :         toc->entries[i].type[5] = 0;
     227          10 :         RPFTOCTrim(toc->entries[i].type);
     228             : 
     229          10 :         bOK &= VSIFReadL(toc->entries[i].compression, 1, 5, fp) == 5;
     230          10 :         toc->entries[i].compression[5] = 0;
     231          10 :         RPFTOCTrim(toc->entries[i].compression);
     232             : 
     233          10 :         bOK &= VSIFReadL(toc->entries[i].scale, 1, 12, fp) == 12;
     234          10 :         toc->entries[i].scale[12] = 0;
     235          10 :         RPFTOCTrim(toc->entries[i].scale);
     236          10 :         if (toc->entries[i].scale[0] == '1' && toc->entries[i].scale[1] == ':')
     237             :         {
     238          10 :             memmove(toc->entries[i].scale, toc->entries[i].scale + 2,
     239          10 :                     strlen(toc->entries[i].scale + 2) + 1);
     240             :         }
     241             : 
     242          10 :         bOK &= VSIFReadL(toc->entries[i].zone, 1, 1, fp) == 1;
     243          10 :         toc->entries[i].zone[1] = 0;
     244          10 :         RPFTOCTrim(toc->entries[i].zone);
     245             : 
     246          10 :         bOK &= VSIFReadL(toc->entries[i].producer, 1, 5, fp) == 5;
     247          10 :         toc->entries[i].producer[5] = 0;
     248          10 :         RPFTOCTrim(toc->entries[i].producer);
     249             : 
     250          10 :         bOK &= VSIFReadL(&toc->entries[i].nwLat, sizeof(double), 1, fp) == 1;
     251          10 :         CPL_MSBPTR64(&toc->entries[i].nwLat);
     252             : 
     253          10 :         bOK &= VSIFReadL(&toc->entries[i].nwLong, sizeof(double), 1, fp) == 1;
     254          10 :         CPL_MSBPTR64(&toc->entries[i].nwLong);
     255             : 
     256          10 :         bOK &= VSIFReadL(&toc->entries[i].swLat, sizeof(double), 1, fp) == 1;
     257          10 :         CPL_MSBPTR64(&toc->entries[i].swLat);
     258             : 
     259          10 :         bOK &= VSIFReadL(&toc->entries[i].swLong, sizeof(double), 1, fp) == 1;
     260          10 :         CPL_MSBPTR64(&toc->entries[i].swLong);
     261             : 
     262          10 :         bOK &= VSIFReadL(&toc->entries[i].neLat, sizeof(double), 1, fp) == 1;
     263          10 :         CPL_MSBPTR64(&toc->entries[i].neLat);
     264             : 
     265          10 :         bOK &= VSIFReadL(&toc->entries[i].neLong, sizeof(double), 1, fp) == 1;
     266          10 :         CPL_MSBPTR64(&toc->entries[i].neLong);
     267             : 
     268          10 :         bOK &= VSIFReadL(&toc->entries[i].seLat, sizeof(double), 1, fp) == 1;
     269          10 :         CPL_MSBPTR64(&toc->entries[i].seLat);
     270             : 
     271          10 :         bOK &= VSIFReadL(&toc->entries[i].seLong, sizeof(double), 1, fp) == 1;
     272          10 :         CPL_MSBPTR64(&toc->entries[i].seLong);
     273             : 
     274          10 :         bOK &= VSIFReadL(&toc->entries[i].vertResolution, sizeof(double), 1,
     275          10 :                          fp) == 1;
     276          10 :         CPL_MSBPTR64(&toc->entries[i].vertResolution);
     277             : 
     278          10 :         bOK &= VSIFReadL(&toc->entries[i].horizResolution, sizeof(double), 1,
     279          10 :                          fp) == 1;
     280          10 :         CPL_MSBPTR64(&toc->entries[i].horizResolution);
     281             : 
     282          10 :         bOK &= VSIFReadL(&toc->entries[i].vertInterval, sizeof(double), 1,
     283          10 :                          fp) == 1;
     284          10 :         CPL_MSBPTR64(&toc->entries[i].vertInterval);
     285             : 
     286          10 :         bOK &= VSIFReadL(&toc->entries[i].horizInterval, sizeof(double), 1,
     287          10 :                          fp) == 1;
     288          10 :         CPL_MSBPTR64(&toc->entries[i].horizInterval);
     289             : 
     290          10 :         bOK &= VSIFReadL(&toc->entries[i].nVertFrames, sizeof(int), 1, fp) == 1;
     291          10 :         CPL_MSBPTR32(&toc->entries[i].nVertFrames);
     292             : 
     293          10 :         bOK &=
     294          10 :             VSIFReadL(&toc->entries[i].nHorizFrames, sizeof(int), 1, fp) == 1;
     295          10 :         CPL_MSBPTR32(&toc->entries[i].nHorizFrames);
     296             : 
     297          10 :         if (!bOK)
     298             :         {
     299           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     300           0 :             toc->entries[i].nVertFrames = 0;
     301           0 :             toc->entries[i].nHorizFrames = 0;
     302           0 :             RPFTOCFree(toc);
     303           0 :             return nullptr;
     304             :         }
     305             : 
     306             :         // do some basic plausibility checks for all entries
     307          30 :         if (toc->entries[i].vertInterval <= 1e-10 ||
     308          10 :             !std::isfinite(toc->entries[i].vertInterval) ||
     309          10 :             toc->entries[i].horizInterval <= 1e-10 ||
     310          10 :             !std::isfinite(toc->entries[i].horizInterval) ||
     311          10 :             toc->entries[i].nHorizFrames == 0 ||
     312          30 :             toc->entries[i].nVertFrames == 0 ||
     313          10 :             toc->entries[i].nHorizFrames >
     314          10 :                 INT_MAX / toc->entries[i].nVertFrames)
     315             :         {
     316           0 :             CPLError(CE_Failure, CPLE_FileIO, "Invalid TOC entry");
     317           0 :             toc->entries[i].nVertFrames = 0;
     318           0 :             toc->entries[i].nHorizFrames = 0;
     319           0 :             RPFTOCFree(toc);
     320           0 :             return nullptr;
     321             :         }
     322             : 
     323             :         // Overview has ZONE 'R' and Legend ZONE 'D' but because the Zone 'D' is
     324             :         // also a valid Zone we need an additional check. -> In all cases of
     325             :         // Overview/Legend the values of the BoundingBox are equal so we simply
     326             :         // check here that NW == SE is.
     327          10 :         toc->entries[i].isOverviewOrLegend =
     328          20 :             (toc->entries[i].zone[0] == 'R' ||   // Overview
     329          10 :              (toc->entries[i].zone[0] == 'D' &&  // Legend
     330           0 :               memcmp(&(toc->entries[i].seLong), &(toc->entries[i].nwLong),
     331           0 :                      sizeof(toc->entries[i].nwLong)) == 0 &&
     332           0 :               memcmp(&(toc->entries[i].seLat), &(toc->entries[i].nwLat),
     333             :                      sizeof(toc->entries[i].nwLat)) == 0));
     334             : 
     335          20 :         bool isPolarZone = (toc->entries[i].zone[0] == '9') ||
     336          10 :                            (toc->entries[i].zone[0] == 'J');
     337             : 
     338             :         // make additional checks of the bounding for charts (without Legends
     339             :         // and Overviews)
     340          10 :         if (!toc->entries[i].isOverviewOrLegend)
     341             :         {
     342          10 :             if (!(fabs(toc->entries[i].seLong) <= 360.0) ||
     343          10 :                 !(fabs(toc->entries[i].nwLong) <= 360.0) ||
     344          10 :                 !(fabs(toc->entries[i].nwLat) <= 90.0) ||
     345          10 :                 !(fabs(toc->entries[i].seLat) <= 90.0) ||
     346             :                 // check only for non-polar zones, because the values are not
     347             :                 // always correct here
     348          10 :                 (!isPolarZone &&
     349          10 :                  (toc->entries[i].seLong < toc->entries[i].nwLong ||
     350          10 :                   toc->entries[i].nwLat < toc->entries[i].seLat)))
     351             :             {
     352           0 :                 CPLError(CE_Failure, CPLE_FileIO, "Invalid TOC entry");
     353           0 :                 toc->entries[i].nVertFrames = 0;
     354           0 :                 toc->entries[i].nHorizFrames = 0;
     355           0 :                 RPFTOCFree(toc);
     356           0 :                 return nullptr;
     357             :             }
     358             :         }
     359             : 
     360             :         // TODO: We could probably use another data structure, like a list,
     361             :         // instead of an array referenced by the frame coordinate...
     362          20 :         if (static_cast<int>(toc->entries[i].nHorizFrames *
     363          20 :                              toc->entries[i].nVertFrames) >
     364          10 :             atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")))
     365             :         {
     366           0 :             CPLError(
     367             :                 CE_Failure, CPLE_AppDefined,
     368             :                 "nHorizFrames=%d x nVertFrames=%d > %d. Please raise "
     369             :                 "the value of the RPFTOC_MAX_FRAME_COUNT configuration "
     370             :                 "option to more than %d if this dataset is legitimate.",
     371           0 :                 toc->entries[i].nHorizFrames, toc->entries[i].nVertFrames,
     372             :                 atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")),
     373           0 :                 toc->entries[i].nHorizFrames * toc->entries[i].nVertFrames);
     374           0 :             toc->entries[i].frameEntries = nullptr;
     375             :         }
     376             :         else
     377             :         {
     378          20 :             toc->entries[i].frameEntries =
     379          10 :                 reinterpret_cast<RPFTocFrameEntry *>(VSI_CALLOC_VERBOSE(
     380             :                     static_cast<size_t>(toc->entries[i].nVertFrames) *
     381             :                         toc->entries[i].nHorizFrames,
     382             :                     sizeof(RPFTocFrameEntry)));
     383             :         }
     384          10 :         if (toc->entries[i].frameEntries == nullptr)
     385             :         {
     386           0 :             toc->entries[i].nVertFrames = 0;
     387           0 :             toc->entries[i].nHorizFrames = 0;
     388           0 :             RPFTOCFree(toc);
     389           0 :             return nullptr;
     390             :         }
     391             : 
     392          10 :         CPLDebug("RPFTOC",
     393             :                  "[%d] type=%s, compression=%s, scale=%s, zone=%s, "
     394             :                  "producer=%s, nVertFrames=%d, nHorizFrames=%d",
     395          10 :                  i, toc->entries[i].type, toc->entries[i].compression,
     396          10 :                  toc->entries[i].scale, toc->entries[i].zone,
     397          10 :                  toc->entries[i].producer, toc->entries[i].nVertFrames,
     398          10 :                  toc->entries[i].nHorizFrames);
     399             :     }
     400             : 
     401          10 :     if (VSIFSeekL(fp, frameFileIndexSectionSubHeaderPhysIndex, SEEK_SET) != 0)
     402             :     {
     403           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     404             :                  "Invalid TOC file. Unable to seek to "
     405             :                  "frameFileIndexSectionSubHeaderPhysIndex at offset %d.",
     406             :                  frameFileIndexSectionSubHeaderPhysIndex);
     407           0 :         RPFTOCFree(toc);
     408           0 :         return nullptr;
     409             :     }
     410             : 
     411             :     /* Skip 1 byte security classification */
     412          10 :     bOK &= VSIFSeekL(fp, 1, SEEK_CUR) == 0;
     413             : 
     414             :     unsigned int frameIndexTableOffset;
     415          10 :     bOK &= VSIFReadL(&frameIndexTableOffset, sizeof(frameIndexTableOffset), 1,
     416          10 :                      fp) == 1;
     417          10 :     CPL_MSBPTR32(&frameIndexTableOffset);
     418             : 
     419             :     unsigned int nFrameFileIndexRecords;
     420          10 :     bOK &= VSIFReadL(&nFrameFileIndexRecords, sizeof(nFrameFileIndexRecords), 1,
     421          10 :                      fp) == 1;
     422          10 :     CPL_MSBPTR32(&nFrameFileIndexRecords);
     423             : 
     424             :     unsigned short nFrameFilePathnameRecords;
     425          10 :     bOK &= VSIFReadL(&nFrameFilePathnameRecords,
     426          10 :                      sizeof(nFrameFilePathnameRecords), 1, fp) == 1;
     427          10 :     CPL_MSBPTR16(&nFrameFilePathnameRecords);
     428             : 
     429             :     unsigned short frameFileIndexRecordLength;
     430          10 :     bOK &= VSIFReadL(&frameFileIndexRecordLength,
     431          10 :                      sizeof(frameFileIndexRecordLength), 1, fp) == 1;
     432          10 :     CPL_MSBPTR16(&frameFileIndexRecordLength);
     433          10 :     if (frameFileIndexRecordLength < 3 * sizeof(short))
     434             :     {
     435           0 :         CPLError(CE_Failure, CPLE_FileIO, "Invalid file");
     436           0 :         RPFTOCFree(toc);
     437           0 :         return nullptr;
     438             :     }
     439             : 
     440          10 :     if (!bOK)
     441             :     {
     442           0 :         CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     443           0 :         RPFTOCFree(toc);
     444           0 :         return nullptr;
     445             :     }
     446             : 
     447          10 :     int newBoundaryId = 0;
     448             : 
     449          20 :     for (int i = 0; i < static_cast<int>(nFrameFileIndexRecords); i++)
     450             :     {
     451          10 :         vsi_l_offset nFrameOffset =
     452          10 :             static_cast<vsi_l_offset>(frameFileIndexSubsectionPhysIndex) +
     453          10 :             static_cast<vsi_l_offset>(frameFileIndexRecordLength) * i;
     454          10 :         if (VSIFSeekL(fp, nFrameOffset, SEEK_SET) != 0)
     455             :         {
     456           0 :             CPLError(
     457             :                 CE_Failure, CPLE_NotSupported,
     458             :                 "Invalid TOC file. Unable to seek to "
     459             :                 "frameFileIndexSubsectionPhysIndex(%d) at offset " CPL_FRMT_GUIB
     460             :                 ".",
     461             :                 i, static_cast<GUIntBig>(nFrameOffset));
     462           0 :             RPFTOCFree(toc);
     463           0 :             return nullptr;
     464             :         }
     465             : 
     466             :         unsigned short boundaryId;
     467          10 :         if (VSIFReadL(&boundaryId, sizeof(boundaryId), 1, fp) != 1)
     468             :         {
     469           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     470           0 :             RPFTOCFree(toc);
     471           0 :             return nullptr;
     472             :         }
     473          10 :         CPL_MSBPTR16(&boundaryId);
     474             : 
     475          10 :         if (i == 0 && boundaryId == 0)
     476          10 :             newBoundaryId = 1;
     477          10 :         if (newBoundaryId == 0)
     478           0 :             boundaryId--;
     479             : 
     480          10 :         if (boundaryId >= toc->nEntries)
     481             :         {
     482           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     483             :                      "Invalid TOC file. Bad boundary id (%d) for frame file "
     484             :                      "index %d.",
     485             :                      boundaryId, i);
     486           0 :             RPFTOCFree(toc);
     487           0 :             return nullptr;
     488             :         }
     489             : 
     490          10 :         RPFTocEntry *entry = &toc->entries[boundaryId];
     491          10 :         entry->boundaryId = boundaryId;
     492             : 
     493             :         unsigned short frameRow;
     494          10 :         bOK &= VSIFReadL(&frameRow, sizeof(frameRow), 1, fp) == 1;
     495          10 :         CPL_MSBPTR16(&frameRow);
     496             : 
     497             :         unsigned short frameCol;
     498          10 :         bOK &= VSIFReadL(&frameCol, sizeof(frameCol), 1, fp) == 1;
     499          10 :         CPL_MSBPTR16(&frameCol);
     500          10 :         if (!bOK)
     501             :         {
     502           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     503           0 :             RPFTOCFree(toc);
     504           0 :             return nullptr;
     505             :         }
     506             : 
     507          10 :         if (newBoundaryId == 0)
     508             :         {
     509           0 :             frameRow--;
     510           0 :             frameCol--;
     511             :         }
     512             :         else
     513             :         {
     514             :             /* Trick so that frames are numbered north to south */
     515          10 :             if (entry->nVertFrames - 1 < frameRow)
     516             :             {
     517           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     518             :                          "Invalid nVertFrames vs frameRow");
     519           0 :                 RPFTOCFree(toc);
     520           0 :                 return nullptr;
     521             :             }
     522          10 :             frameRow = (unsigned short)((entry->nVertFrames - 1) - frameRow);
     523             :         }
     524             : 
     525          10 :         if (frameRow >= entry->nVertFrames)
     526             :         {
     527           0 :             CPLError(
     528             :                 CE_Failure, CPLE_NotSupported,
     529             :                 "Invalid TOC file. Bad row num (%d) for frame file index %d.",
     530             :                 frameRow, i);
     531           0 :             RPFTOCFree(toc);
     532           0 :             return nullptr;
     533             :         }
     534             : 
     535          10 :         if (frameCol >= entry->nHorizFrames)
     536             :         {
     537           0 :             CPLError(
     538             :                 CE_Failure, CPLE_NotSupported,
     539             :                 "Invalid TOC file. Bad col num (%d) for frame file index %d.",
     540             :                 frameCol, i);
     541           0 :             RPFTOCFree(toc);
     542           0 :             return nullptr;
     543             :         }
     544             : 
     545          10 :         RPFTocFrameEntry *frameEntry =
     546          10 :             &entry->frameEntries[frameRow * entry->nHorizFrames + frameCol];
     547          10 :         frameEntry->frameRow = frameRow;
     548          10 :         frameEntry->frameCol = frameCol;
     549             : 
     550          10 :         if (frameEntry->exists)
     551             :         {
     552           0 :             CPLError(
     553             :                 CE_Warning, CPLE_AppDefined,
     554             :                 "Frame entry(%d,%d) for frame file index %d was already found.",
     555             :                 frameRow, frameCol, i);
     556           0 :             CPLFree(frameEntry->directory);
     557           0 :             frameEntry->directory = nullptr;
     558           0 :             CPLFree(frameEntry->fullFilePath);
     559           0 :             frameEntry->fullFilePath = nullptr;
     560           0 :             frameEntry->exists = 0;
     561             :         }
     562             : 
     563             :         unsigned int offsetFrameFilePathName;
     564          10 :         bOK &= VSIFReadL(&offsetFrameFilePathName,
     565          10 :                          sizeof(offsetFrameFilePathName), 1, fp) == 1;
     566          10 :         CPL_MSBPTR32(&offsetFrameFilePathName);
     567             : 
     568          10 :         bOK &= VSIFReadL(frameEntry->filename, 1, 12, fp) == 12;
     569          10 :         if (!bOK)
     570             :         {
     571           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     572           0 :             RPFTOCFree(toc);
     573           0 :             return nullptr;
     574             :         }
     575          10 :         frameEntry->filename[12] = '\0';
     576          10 :         bOK &= strlen(frameEntry->filename) > 0;
     577             : 
     578             :         // Check (case insensitive) if the filename is an overview or legend
     579             :         // some CADRG maps have legend name smaller than 8.3 then the extension
     580             :         // has blanks (0x20) at the end -> check only the first 3 letters of the
     581             :         // extension.
     582          10 :         const char *fileExt = CPLGetExtension(frameEntry->filename);
     583          10 :         if (EQUALN(fileExt, "ovr", 3) || EQUALN(fileExt, "lgd", 3))
     584             :         {
     585           0 :             entry->isOverviewOrLegend = TRUE;
     586             :         }
     587             : 
     588             :         /* Extract series code */
     589          10 :         if (entry->seriesAbbreviation == nullptr)
     590             :         {
     591          10 :             const NITFSeries *series = NITFGetSeriesInfo(frameEntry->filename);
     592          10 :             if (series)
     593             :             {
     594          10 :                 entry->seriesAbbreviation = series->abbreviation;
     595          10 :                 entry->seriesName = series->name;
     596             :             }
     597             :         }
     598             : 
     599             :         /* Get file geo reference */
     600          10 :         bOK &= VSIFReadL(frameEntry->georef, 1, 6, fp) == 6;
     601          10 :         frameEntry->georef[6] = '\0';
     602             : 
     603             :         /* Go to start of pathname record */
     604             :         /* New path_off offset from start of frame file index section of TOC??
     605             :          */
     606             :         /* Add pathoffset wrt frame file index table subsection (loc[3]) */
     607          20 :         if (!bOK || VSIFSeekL(fp,
     608          10 :                               static_cast<vsi_l_offset>(
     609             :                                   frameFileIndexSubsectionPhysIndex) +
     610          10 :                                   offsetFrameFilePathName,
     611             :                               SEEK_SET) != 0)
     612             :         {
     613           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     614             :                      "Invalid TOC file. Unable to seek to "
     615             :                      "frameFileIndexSubsectionPhysIndex + "
     616             :                      "offsetFrameFilePathName(%d) at offset " CPL_FRMT_GUIB ".",
     617             :                      i,
     618           0 :                      static_cast<GUIntBig>(frameFileIndexSubsectionPhysIndex) +
     619           0 :                          offsetFrameFilePathName);
     620           0 :             RPFTOCFree(toc);
     621           0 :             return nullptr;
     622             :         }
     623             : 
     624             :         unsigned short pathLength;
     625          10 :         bOK &= VSIFReadL(&pathLength, sizeof(pathLength), 1, fp) == 1;
     626          10 :         CPL_MSBPTR16(&pathLength);
     627             : 
     628             :         /* if nFrameFileIndexRecords == 65535 and pathLength == 65535 for each
     629             :            record, this leads to 4 GB allocation... Protect against this case */
     630          10 :         if (!bOK || pathLength == 0 || pathLength > 256)
     631             :         {
     632           0 :             CPLError(
     633             :                 CE_Failure, CPLE_NotSupported,
     634             :                 "Path length is invalid : %d. Probably corrupted TOC file.",
     635             :                 static_cast<int>(pathLength));
     636           0 :             RPFTOCFree(toc);
     637           0 :             return nullptr;
     638             :         }
     639             : 
     640          10 :         frameEntry->directory =
     641          10 :             reinterpret_cast<char *>(CPLMalloc(pathLength + 1));
     642          10 :         bOK &=
     643          10 :             VSIFReadL(frameEntry->directory, 1, pathLength, fp) == pathLength;
     644          10 :         if (!bOK)
     645             :         {
     646           0 :             CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     647           0 :             RPFTOCFree(toc);
     648           0 :             return nullptr;
     649             :         }
     650          10 :         frameEntry->directory[pathLength] = 0;
     651          10 :         if (frameEntry->directory[pathLength - 1] == '/')
     652          10 :             frameEntry->directory[pathLength - 1] = 0;
     653             : 
     654          10 :         if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == '/')
     655             :         {
     656           0 :             memmove(frameEntry->directory, frameEntry->directory + 2,
     657           0 :                     strlen(frameEntry->directory + 2) + 1);
     658             : 
     659             :             // Some A.TOC have subdirectory names like ".//X/" ... (#5979)
     660             :             // Check if it was not intended to be "./X/" instead.
     661             :             VSIStatBufL sStatBuf;
     662           0 :             if (frameEntry->directory[0] == '/' &&
     663           0 :                 VSIStatL(CPLFormFilename(CPLGetDirname(pszFilename),
     664           0 :                                          frameEntry->directory + 1, nullptr),
     665           0 :                          &sStatBuf) == 0 &&
     666           0 :                 VSI_ISDIR(sStatBuf.st_mode))
     667             :             {
     668           0 :                 memmove(frameEntry->directory, frameEntry->directory + 1,
     669           0 :                         strlen(frameEntry->directory + 1) + 1);
     670             :             }
     671             :         }
     672             : 
     673             :         {
     674          10 :             char *baseDir = CPLStrdup(CPLGetDirname(pszFilename));
     675             :             VSIStatBufL sStatBuf;
     676          10 :             char *subdir = nullptr;
     677          10 :             if (CPLIsFilenameRelative(frameEntry->directory) == FALSE)
     678           0 :                 subdir = CPLStrdup(frameEntry->directory);
     679          10 :             else if (frameEntry->directory[0] == '.' &&
     680          10 :                      frameEntry->directory[1] == 0)
     681          10 :                 subdir = CPLStrdup(baseDir);
     682             :             else
     683           0 :                 subdir = CPLStrdup(
     684           0 :                     CPLFormFilename(baseDir, frameEntry->directory, nullptr));
     685             : #if !defined(_WIN32) && !defined(_WIN32_CE)
     686          10 :             if (VSIStatL(subdir, &sStatBuf) != 0 &&
     687           0 :                 strlen(subdir) > strlen(baseDir))
     688             :             {
     689           0 :                 char *c = subdir + strlen(baseDir) + 1;
     690           0 :                 while (*c)
     691             :                 {
     692           0 :                     if (*c >= 'A' && *c <= 'Z')
     693           0 :                         *c += 'a' - 'A';
     694           0 :                     c++;
     695             :                 }
     696             :             }
     697             : #endif
     698          10 :             frameEntry->fullFilePath = CPLStrdup(
     699          10 :                 CPLFormFilename(subdir, frameEntry->filename, nullptr));
     700          10 :             if (VSIStatL(frameEntry->fullFilePath, &sStatBuf) != 0)
     701             :             {
     702             : #if !defined(_WIN32) && !defined(_WIN32_CE)
     703           0 :                 if (strlen(frameEntry->fullFilePath) > strlen(subdir))
     704             :                 {
     705           0 :                     char *c = frameEntry->fullFilePath + strlen(subdir) + 1;
     706           0 :                     while (*c)
     707             :                     {
     708           0 :                         if (*c >= 'A' && *c <= 'Z')
     709           0 :                             *c += 'a' - 'A';
     710           0 :                         c++;
     711             :                     }
     712             :                 }
     713           0 :                 if (VSIStatL(frameEntry->fullFilePath, &sStatBuf) != 0)
     714             : #endif
     715             :                 {
     716           0 :                     frameEntry->fileExists = 0;
     717           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     718             :                              "File %s does not exist.",
     719             :                              frameEntry->fullFilePath);
     720             :                 }
     721             : #if !defined(_WIN32) && !defined(_WIN32_CE)
     722             :                 else
     723             :                 {
     724           0 :                     frameEntry->fileExists = 1;
     725             :                 }
     726             : #endif
     727             :             }
     728             :             else
     729             :             {
     730          10 :                 frameEntry->fileExists = 1;
     731             :             }
     732          10 :             CPLFree(subdir);
     733          10 :             CPLFree(baseDir);
     734             :         }
     735             : 
     736          10 :         CPLDebug("RPFTOC", "Entry %d : %s,%s (%d, %d)", boundaryId,
     737          10 :                  frameEntry->directory, frameEntry->filename, frameRow,
     738             :                  frameCol);
     739             : 
     740          10 :         frameEntry->exists = 1;
     741             :     }
     742             : 
     743          10 :     return toc;
     744             : }
     745             : 
     746             : /************************************************************************/
     747             : /*                        RPFTOCFree()                                 */
     748             : /************************************************************************/
     749             : 
     750          10 : void RPFTOCFree(RPFToc *toc)
     751             : {
     752          10 :     if (!toc)
     753           0 :         return;
     754             : 
     755          20 :     for (int i = 0; i < toc->nEntries; i++)
     756             :     {
     757          20 :         for (int j = 0; j < static_cast<int>(toc->entries[i].nVertFrames *
     758          20 :                                              toc->entries[i].nHorizFrames);
     759             :              j++)
     760             :         {
     761          10 :             CPLFree(toc->entries[i].frameEntries[j].fullFilePath);
     762          10 :             CPLFree(toc->entries[i].frameEntries[j].directory);
     763             :         }
     764          10 :         CPLFree(toc->entries[i].frameEntries);
     765             :     }
     766             : 
     767          10 :     CPLFree(toc->entries);
     768          10 :     CPLFree(toc);
     769             : }

Generated by: LCOV version 1.14