Example #1
0
int main( int nArgc, char ** papszArgv )

{
    NITFFile	*psFile;
    int          iSegment, iFile;
    char         szTemp[100];
    int          bDisplayTRE = FALSE;
    int          bExtractSHP = FALSE, bExtractSHPInMem = FALSE;

    if( nArgc < 2 )
    {
        printf( "Usage: nitfdump [-tre] [-extractshp | -extractshpinmem] <nitf_filename>*\n" );
        exit( 1 );
    }

    for( iFile = 1; iFile < nArgc; iFile++ )
    {
        if ( EQUAL(papszArgv[iFile], "-tre") )
            bDisplayTRE = TRUE;
        else if ( EQUAL(papszArgv[iFile], "-extractshp") )
            bExtractSHP = TRUE;
        else if ( EQUAL(papszArgv[iFile], "-extractshpinmem") )
        {
            bExtractSHP = TRUE;
            bExtractSHPInMem = TRUE;
        }
    }

/* ==================================================================== */
/*      Loop over all files.                                            */
/* ==================================================================== */
    for( iFile = 1; iFile < nArgc; iFile++ )
    {
        int bHasFoundLocationTable = FALSE;

        if ( EQUAL(papszArgv[iFile], "-tre") )
            continue;
        if ( EQUAL(papszArgv[iFile], "-extractshp") )
            continue;
        if ( EQUAL(papszArgv[iFile], "-extractshpinmem") )
            continue;

/* -------------------------------------------------------------------- */
/*      Open the file.                                                  */
/* -------------------------------------------------------------------- */
        psFile = NITFOpen( papszArgv[iFile], FALSE );
        if( psFile == NULL )
            exit( 2 );

        printf( "Dump for %s\n", papszArgv[iFile] );

/* -------------------------------------------------------------------- */
/*      Dump first TRE list.                                            */
/* -------------------------------------------------------------------- */
        if( psFile->pachTRE != NULL )
        {
            int nTREBytes = psFile->nTREBytes;
            const char *pszTREData = psFile->pachTRE;


            printf( "File TREs:" );

            while( nTREBytes > 10 )
            {
                int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
                if (nThisTRESize < 0 || nThisTRESize > nTREBytes - 11)
                {
                    NITFGetField(szTemp, pszTREData, 0, 6 );
                    printf(" Invalid size (%d) for TRE %s", nThisTRESize, szTemp);
                    break;
                }

                printf( " %6.6s(%d)", pszTREData, nThisTRESize );
                pszTREData += nThisTRESize + 11;
                nTREBytes -= (nThisTRESize + 11);
            }
            printf( "\n" );

            if (bDisplayTRE)
            {
                nTREBytes = psFile->nTREBytes;
                pszTREData = psFile->pachTRE;

                while( nTREBytes > 10 )
                {
                    char *pszEscaped;
                    int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
                    if (nThisTRESize < 0 || nThisTRESize > nTREBytes - 11)
                    {
                        break;
                    }

                    pszEscaped = CPLEscapeString( pszTREData + 11, nThisTRESize,
                                                       CPLES_BackslashQuotable );
                    printf( "TRE '%6.6s' : %s\n", pszTREData, pszEscaped);
                    CPLFree(pszEscaped);

                    pszTREData += nThisTRESize + 11;
                    nTREBytes -= (nThisTRESize + 11);
                }
            }
        }

/* -------------------------------------------------------------------- */
/*      Dump Metadata                                                   */
/* -------------------------------------------------------------------- */
        DumpMetadata( "File Metadata:", "  ", psFile->papszMetadata );

/* -------------------------------------------------------------------- */
/*      Dump general info about segments.                               */
/* -------------------------------------------------------------------- */
        NITFCollectAttachments( psFile );
        NITFReconcileAttachments( psFile );

        for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
        {
            NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;

            printf( "Segment %d (Type=%s):\n",
                    iSegment + 1, psSegInfo->szSegmentType );

            printf( "  HeaderStart=" CPL_FRMT_GUIB ", HeaderSize=%u, DataStart=" CPL_FRMT_GUIB ", DataSize=" CPL_FRMT_GUIB "\n",
                    psSegInfo->nSegmentHeaderStart,
                    psSegInfo->nSegmentHeaderSize,
                    psSegInfo->nSegmentStart,
                    psSegInfo->nSegmentSize );
            printf( "  DLVL=%d, ALVL=%d, LOC=C%d,R%d, CCS=C%d,R%d\n",
                    psSegInfo->nDLVL,
                    psSegInfo->nALVL,
                    psSegInfo->nLOC_C,
                    psSegInfo->nLOC_R,
                    psSegInfo->nCCS_C,
                    psSegInfo->nCCS_R );
            printf( "\n" );
        }

/* -------------------------------------------------------------------- */
/*      Report details of images.                                       */
/* -------------------------------------------------------------------- */
        for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
        {
            NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
            NITFImage *psImage;
            NITFRPC00BInfo sRPCInfo;
            int iBand;
            char **papszMD;

            if( !EQUAL(psSegInfo->szSegmentType,"IM") )
                continue;

            psImage = NITFImageAccess( psFile, iSegment );
            if( psImage == NULL )
            {
                printf( "NITFAccessImage(%d) failed!\n", iSegment );
                continue;
            }

            printf( "Image Segment %d, %dPx%dLx%dB x %dbits:\n",
                    iSegment + 1, psImage->nCols, psImage->nRows,
                    psImage->nBands, psImage->nBitsPerSample );
            printf( "  PVTYPE=%s, IREP=%s, ICAT=%s, IMODE=%c, IC=%s, COMRAT=%s, ICORDS=%c\n",
                    psImage->szPVType, psImage->szIREP, psImage->szICAT,
                    psImage->chIMODE, psImage->szIC, psImage->szCOMRAT,
                    psImage->chICORDS );
            if( psImage->chICORDS != ' ' )
            {
                printf( "  UL=(%.15g,%.15g), UR=(%.15g,%.15g) Center=%d\n  LL=(%.15g,%.15g), LR=(%.15g,%.15g)\n",
                        psImage->dfULX, psImage->dfULY,
                        psImage->dfURX, psImage->dfURY,
                        psImage->bIsBoxCenterOfPixel,
                        psImage->dfLLX, psImage->dfLLY,
                        psImage->dfLRX, psImage->dfLRY );
            }

            printf( "  IDLVL=%d, IALVL=%d, ILOC R=%d,C=%d, IMAG=%s\n",
                    psImage->nIDLVL, psImage->nIALVL,
                    psImage->nILOCRow, psImage->nILOCColumn,
                    psImage->szIMAG );

            printf( "  %d x %d blocks of size %d x %d\n",
                    psImage->nBlocksPerRow, psImage->nBlocksPerColumn,
                    psImage->nBlockWidth, psImage->nBlockHeight );

            if( psImage->pachTRE != NULL )
            {
                int nTREBytes = psImage->nTREBytes;
                const char *pszTREData = psImage->pachTRE;

                printf( "  Image TREs:" );

                while( nTREBytes > 10 )
                {
                    int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
                    if (nThisTRESize < 0 || nThisTRESize > nTREBytes - 11)
                    {
                        NITFGetField(szTemp, pszTREData, 0, 6 );
                        printf(" Invalid size (%d) for TRE %s", nThisTRESize, szTemp);
                        break;
                    }

                    printf( " %6.6s(%d)", pszTREData, nThisTRESize );
                    pszTREData += nThisTRESize + 11;
                    nTREBytes -= (nThisTRESize + 11);
                }
                printf( "\n" );

                if (bDisplayTRE)
                {
                    nTREBytes = psImage->nTREBytes;
                    pszTREData = psImage->pachTRE;

                    while( nTREBytes > 10 )
                    {
                        char *pszEscaped;
                        int nThisTRESize = atoi(NITFGetField(szTemp, pszTREData, 6, 5 ));
                        if (nThisTRESize < 0 || nThisTRESize > nTREBytes - 11)
                        {
                            break;
                        }

                        pszEscaped = CPLEscapeString( pszTREData + 11, nThisTRESize,
                                                        CPLES_BackslashQuotable );
                        printf( "  TRE '%6.6s' : %s\n", pszTREData, pszEscaped);
                        CPLFree(pszEscaped);

                        pszTREData += nThisTRESize + 11;
                        nTREBytes -= (nThisTRESize + 11);
                    }
                }
            }

            /* Report info from location table, if found.                  */
            if( psImage->nLocCount > 0 )
            {
                int i;
                bHasFoundLocationTable = TRUE;
                printf( "  Location Table\n" );
                for( i = 0; i < psImage->nLocCount; i++ )
                {
                    printf( "    LocName=%s, LocId=%d, Offset=%d, Size=%d\n",
                            GetLocationNameFromId(psImage->pasLocations[i].nLocId),
                            psImage->pasLocations[i].nLocId,
                            psImage->pasLocations[i].nLocOffset,
                            psImage->pasLocations[i].nLocSize );
                }
                printf( "\n" );
            }

            if( strlen(psImage->pszComments) > 0 )
                printf( "  Comments:\n%s\n", psImage->pszComments );

            for( iBand = 0; iBand < psImage->nBands; iBand++ )
            {
                NITFBandInfo *psBandInfo = psImage->pasBandInfo + iBand;

                printf( "  Band %d: IREPBAND=%s, ISUBCAT=%s, %d LUT entries.\n",
                        iBand + 1, psBandInfo->szIREPBAND, psBandInfo->szISUBCAT,
                        psBandInfo->nSignificantLUTEntries );
            }

            if( NITFReadRPC00B( psImage, &sRPCInfo ) )
            {
                DumpRPC( psImage, &sRPCInfo );
            }

            papszMD = NITFReadUSE00A( psImage );
            if( papszMD != NULL )
            {
                DumpMetadata( "  USE00A TRE:", "    ", papszMD );
                CSLDestroy( papszMD );
            }

            papszMD = NITFReadBLOCKA( psImage );
            if( papszMD != NULL )
            {
                DumpMetadata( "  BLOCKA TRE:", "    ", papszMD );
                CSLDestroy( papszMD );
            }

            papszMD = NITFReadSTDIDC( psImage );
            if( papszMD != NULL )
            {
                DumpMetadata( "  STDIDC TRE:", "    ", papszMD );
                CSLDestroy( papszMD );
            }

            DumpMetadata( "  Image Metadata:", "    ", psImage->papszMetadata );
            printf("\n");
        }

/* ==================================================================== */
/*      Report details of graphic segments.                             */
/* ==================================================================== */
        for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
        {
            NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
            char achSubheader[298];
            int  nSTYPEOffset;

            if( !EQUAL(psSegInfo->szSegmentType,"GR")
                && !EQUAL(psSegInfo->szSegmentType,"SY") )
                continue;

/* -------------------------------------------------------------------- */
/*      Load the graphic subheader.                                     */
/* -------------------------------------------------------------------- */
            if( VSIFSeekL( psFile->fp, psSegInfo->nSegmentHeaderStart,
                           SEEK_SET ) != 0
                || VSIFReadL( achSubheader, 1, sizeof(achSubheader),
                              psFile->fp ) < 258 )
            {
                CPLError( CE_Warning, CPLE_FileIO,
                          "Failed to read graphic subheader at " CPL_FRMT_GUIB ".",
                          psSegInfo->nSegmentHeaderStart );
                continue;
            }

            // NITF 2.0. (also works for NITF 2.1)
            nSTYPEOffset = 200;
            if( STARTS_WITH_CI(achSubheader+193, "999998") )
                nSTYPEOffset += 40;

/* -------------------------------------------------------------------- */
/*      Report some standard info.                                      */
/* -------------------------------------------------------------------- */
            printf( "Graphic Segment %d, type=%2.2s, sfmt=%c, sid=%10.10s\n",
                    iSegment + 1,
                    achSubheader + 0,
                    achSubheader[nSTYPEOffset],
                    achSubheader + 2 );

            printf( "  sname=%20.20s\n", achSubheader + 12 );
            printf("\n");
        }

/* ==================================================================== */
/*      Report details of text segments.                                */
/* ==================================================================== */
        for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
        {
            char *pabyHeaderData;
            char *pabyTextData;

            NITFSegmentInfo *psSegment = psFile->pasSegmentInfo + iSegment;

            if( !EQUAL(psSegment->szSegmentType,"TX") )
                continue;

            printf( "Text Segment %d\n", iSegment + 1);

/* -------------------------------------------------------------------- */
/*      Load the text header                                            */
/* -------------------------------------------------------------------- */

            /* Allocate one extra byte for the NULL terminating character */
            pabyHeaderData = (char *) CPLCalloc(1,
                    (size_t) psSegment->nSegmentHeaderSize + 1);
            if (VSIFSeekL(psFile->fp, psSegment->nSegmentHeaderStart,
                        SEEK_SET) != 0 ||
                VSIFReadL(pabyHeaderData, 1, (size_t) psSegment->nSegmentHeaderSize,
                        psFile->fp) != psSegment->nSegmentHeaderSize)
            {
                CPLError( CE_Warning, CPLE_FileIO,
                        "Failed to read %d bytes of text header data at " CPL_FRMT_GUIB ".",
                        psSegment->nSegmentHeaderSize,
                        psSegment->nSegmentHeaderStart);
                CPLFree(pabyHeaderData);
                continue;
            }

            printf("  Header : %s\n", pabyHeaderData);
            CPLFree(pabyHeaderData);

/* -------------------------------------------------------------------- */
/*      Load the raw TEXT data itself.                                  */
/* -------------------------------------------------------------------- */


            /* Allocate one extra byte for the NULL terminating character */
            pabyTextData = (char *) CPLCalloc(1,(size_t)psSegment->nSegmentSize+1);
            if( VSIFSeekL( psFile->fp, psSegment->nSegmentStart,
                        SEEK_SET ) != 0
                || VSIFReadL( pabyTextData, 1, (size_t)psSegment->nSegmentSize,
                            psFile->fp ) != psSegment->nSegmentSize )
            {
                CPLError( CE_Warning, CPLE_FileIO,
                        "Failed to read " CPL_FRMT_GUIB " bytes of text data at " CPL_FRMT_GUIB ".",
                        psSegment->nSegmentSize,
                        psSegment->nSegmentStart );
                CPLFree( pabyTextData );
                continue;
            }

            printf("  Data  : %s\n", pabyTextData);
            printf("\n");
            CPLFree( pabyTextData );

        }

/* -------------------------------------------------------------------- */
/*      Report details of DES.                                          */
/* -------------------------------------------------------------------- */
        for( iSegment = 0; iSegment < psFile->nSegmentCount; iSegment++ )
        {
            NITFSegmentInfo *psSegInfo = psFile->pasSegmentInfo + iSegment;
            NITFDES *psDES;
            int nOffset = 0;
            char szTREName[7];
            int nThisTRESize;
            int nRPFDESOffset = -1;

            if( !EQUAL(psSegInfo->szSegmentType,"DE") )
                continue;

            psDES = NITFDESAccess( psFile, iSegment );
            if( psDES == NULL )
            {
                printf( "NITFDESAccess(%d) failed!\n", iSegment );
                continue;
            }

            printf( "DE Segment %d:\n", iSegment + 1 );

            printf( "  Segment TREs:" );
            nOffset = 0;
            while (NITFDESGetTRE( psDES, nOffset, szTREName, NULL, &nThisTRESize))
            {
                printf( " %6.6s(%d)", szTREName, nThisTRESize );
                if (strcmp(szTREName, "RPFDES") == 0)
                    nRPFDESOffset = nOffset + 11;
                nOffset += 11 + nThisTRESize;
            }
            printf( "\n" );

            if (bDisplayTRE)
            {
                char* pabyTREData = NULL;
                nOffset = 0;
                while (NITFDESGetTRE( psDES, nOffset, szTREName, &pabyTREData, &nThisTRESize))
                {
                    char* pszEscaped = CPLEscapeString( pabyTREData, nThisTRESize,
                                                        CPLES_BackslashQuotable );
                    printf( "  TRE '%6.6s' : %s\n", szTREName, pszEscaped);
                    CPLFree(pszEscaped);

                    nOffset += 11 + nThisTRESize;

                    NITFDESFreeTREData(pabyTREData);
                }
            }

            /* Report info from location table, if found. */
            if( !bHasFoundLocationTable && nRPFDESOffset >= 0 )
            {
                int i;
                int nLocCount = 0;
                NITFLocation* pasLocations;

                VSIFSeekL(psFile->fp, psSegInfo->nSegmentStart + nRPFDESOffset, SEEK_SET);
                pasLocations = NITFReadRPFLocationTable(psFile->fp, &nLocCount);
                if (pasLocations)
                {
                    printf( "  Location Table\n" );
                    for( i = 0; i < nLocCount; i++ )
                    {
                        printf( "    LocName=%s, LocId=%d, Offset=%d, Size=%d\n",
                                GetLocationNameFromId(pasLocations[i].nLocId),
                                pasLocations[i].nLocId,
                                pasLocations[i].nLocOffset,
                                pasLocations[i].nLocSize );
                    }

                    CPLFree(pasLocations);
                    printf( "\n" );
                }
            }

            DumpMetadata( "  DES Metadata:", "    ", psDES->papszMetadata );

            if ( bExtractSHP && CSLFetchNameValue(psDES->papszMetadata, "NITF_SHAPE_USE") != NULL )
            {
                char szFilename[32];
                char szRadix[32];
                if (bExtractSHPInMem)
                    snprintf(szRadix, sizeof(szRadix), "/vsimem/nitf_segment_%d", iSegment + 1);
                else
                    snprintf(szRadix, sizeof(szRadix), "nitf_segment_%d", iSegment + 1);

                if (NITFDESExtractShapefile(psDES, szRadix))
                {
                    OGRDataSourceH hDS;
                    OGRRegisterAll();
                    snprintf(szFilename, sizeof(szFilename), "%s.SHP", szRadix);
                    hDS = OGROpen(szFilename, FALSE, NULL);
                    if (hDS)
                    {
                        int nGeom = 0;
                        OGRLayerH hLayer = OGR_DS_GetLayer(hDS, 0);
                        if (hLayer)
                        {
                            OGRFeatureH hFeat;
                            printf("\n");
                            while ( (hFeat = OGR_L_GetNextFeature(hLayer)) != NULL )
                            {
                                OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat);
                                if (hGeom)
                                {
                                    char* pszWKT = NULL;
                                    OGR_G_ExportToWkt(hGeom, &pszWKT);
                                    if (pszWKT)
                                        printf("    Geometry %d : %s\n", nGeom ++, pszWKT);
                                    CPLFree(pszWKT);
                                }
                                OGR_F_Destroy(hFeat);
                            }
                        }
                        OGR_DS_Destroy(hDS);
                    }
                }

                if (bExtractSHPInMem)
                {
                    snprintf(szFilename, sizeof(szFilename), "%s.SHP", szRadix);
                    VSIUnlink(szFilename);
                    snprintf(szFilename, sizeof(szFilename), "%s.SHX", szRadix);
                    VSIUnlink(szFilename);
                    snprintf(szFilename, sizeof(szFilename), "%s.DBF", szRadix);
                    VSIUnlink(szFilename);
                }
            }
        }

/* -------------------------------------------------------------------- */
/*      Close.                                                          */
/* -------------------------------------------------------------------- */
        NITFClose( psFile );
    }

    CPLFinderClean();
    CPLCleanupTLS();
    VSICleanupFileManager();
    OGRCleanupAll();

    exit( 0 );
}
Example #2
0
RPFToc* RPFTOCReadFromBuffer(const char* pszFilename, VSILFILE* fp, const char* tocHeader)
{
    tocHeader += 1; /* skip endian */
    tocHeader += 2; /* skip header length */
    tocHeader += 12; /* skip file name : this should be A.TOC (padded) */
    tocHeader += 1; /* skip new  */
    tocHeader += 15; /* skip standard_num  */
    tocHeader += 8; /* skip standard_date  */
    tocHeader += 1; /* skip classification  */
    tocHeader += 2; /* skip country  */
    tocHeader += 2; /* skip release  */

    unsigned int locationSectionPhysicalLocation;
    memcpy(&locationSectionPhysicalLocation, tocHeader, sizeof(unsigned int));
    CPL_MSBPTR32(&locationSectionPhysicalLocation);

    if( VSIFSeekL( fp, locationSectionPhysicalLocation, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Unable to seek to locationSectionPhysicalLocation at offset %d.",
                   locationSectionPhysicalLocation );
        return nullptr;
    }

    int nSections;
    NITFLocation* pasLocations = NITFReadRPFLocationTable(fp, &nSections);

    unsigned int boundaryRectangleSectionSubHeaderPhysIndex = 0;
    unsigned int boundaryRectangleTablePhysIndex = 0;
    unsigned int frameFileIndexSectionSubHeaderPhysIndex = 0;
    unsigned int frameFileIndexSubsectionPhysIndex = 0;

    for( int i = 0; i < nSections; i++ )
    {
        if (pasLocations[i].nLocId == LID_BoundaryRectangleSectionSubheader)
        {
            boundaryRectangleSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset;
        }
        else if (pasLocations[i].nLocId == LID_BoundaryRectangleTable)
        {
            boundaryRectangleTablePhysIndex = pasLocations[i].nLocOffset;
        }
        else if (pasLocations[i].nLocId == LID_FrameFileIndexSectionSubHeader)
        {
            frameFileIndexSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset;
        }
        else if (pasLocations[i].nLocId == LID_FrameFileIndexSubsection)
        {
            frameFileIndexSubsectionPhysIndex = pasLocations[i].nLocOffset;
        }
    }

    CPLFree(pasLocations);

    if (boundaryRectangleSectionSubHeaderPhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Can't find LID_BoundaryRectangleSectionSubheader." );
        return nullptr;
    }
    if (boundaryRectangleTablePhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Can't find LID_BoundaryRectangleTable." );
        return nullptr;
    }
    if (frameFileIndexSectionSubHeaderPhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Can't find LID_FrameFileIndexSectionSubHeader." );
        return nullptr;
    }
    if (frameFileIndexSubsectionPhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Can't find LID_FrameFileIndexSubsection." );
        return nullptr;
    }

    if( VSIFSeekL( fp, boundaryRectangleSectionSubHeaderPhysIndex, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Unable to seek to boundaryRectangleSectionSubHeaderPhysIndex at offset %d.",
                   boundaryRectangleSectionSubHeaderPhysIndex );
        return nullptr;
    }

    unsigned int boundaryRectangleTableOffset;
    bool bOK = VSIFReadL( &boundaryRectangleTableOffset, sizeof(boundaryRectangleTableOffset), 1, fp) == 1;
    CPL_MSBPTR32( &boundaryRectangleTableOffset );

    unsigned short boundaryRectangleCount;
    bOK &= VSIFReadL( &boundaryRectangleCount, sizeof(boundaryRectangleCount), 1, fp) == 1;
    CPL_MSBPTR16( &boundaryRectangleCount );

    if( !bOK || VSIFSeekL( fp, boundaryRectangleTablePhysIndex, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Unable to seek to boundaryRectangleTablePhysIndex at offset %d.",
                   boundaryRectangleTablePhysIndex );
        return nullptr;
    }

    RPFToc* toc = reinterpret_cast<RPFToc *>( CPLMalloc( sizeof( RPFToc ) ) );
    toc->nEntries = boundaryRectangleCount;
    toc->entries = reinterpret_cast<RPFTocEntry *>(
        CPLMalloc( boundaryRectangleCount * sizeof(RPFTocEntry) ) );
    memset(toc->entries, 0, boundaryRectangleCount * sizeof(RPFTocEntry));

    for( int i = 0; i < toc->nEntries; i++ )
    {
        toc->entries[i].isOverviewOrLegend = 0;

        bOK &= VSIFReadL( toc->entries[i].type, 1, 5, fp) == 5;
        toc->entries[i].type[5] = 0;
        RPFTOCTrim(toc->entries[i].type);

        bOK &= VSIFReadL( toc->entries[i].compression, 1, 5, fp) == 5;
        toc->entries[i].compression[5] = 0;
        RPFTOCTrim(toc->entries[i].compression);

        bOK &= VSIFReadL( toc->entries[i].scale, 1, 12, fp) == 12;
        toc->entries[i].scale[12] = 0;
        RPFTOCTrim(toc->entries[i].scale);
        if (toc->entries[i].scale[0] == '1' &&
            toc->entries[i].scale[1] == ':')
        {
            memmove(toc->entries[i].scale,
                    toc->entries[i].scale+2,
                    strlen(toc->entries[i].scale+2)+1);
        }

        bOK &= VSIFReadL( toc->entries[i].zone, 1, 1, fp) == 1;
        toc->entries[i].zone[1] = 0;
        RPFTOCTrim(toc->entries[i].zone);

        bOK &= VSIFReadL( toc->entries[i].producer, 1, 5, fp) == 5;
        toc->entries[i].producer[5] = 0;
        RPFTOCTrim(toc->entries[i].producer);

        bOK &= VSIFReadL( &toc->entries[i].nwLat, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].nwLat);

        bOK &= VSIFReadL( &toc->entries[i].nwLong, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].nwLong);

        bOK &= VSIFReadL( &toc->entries[i].swLat, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].swLat);

        bOK &= VSIFReadL( &toc->entries[i].swLong, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].swLong);

        bOK &= VSIFReadL( &toc->entries[i].neLat, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].neLat);

        bOK &= VSIFReadL( &toc->entries[i].neLong, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].neLong);

        bOK &= VSIFReadL( &toc->entries[i].seLat, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].seLat);

        bOK &= VSIFReadL( &toc->entries[i].seLong, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].seLong);

        bOK &= VSIFReadL( &toc->entries[i].vertResolution, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].vertResolution);

        bOK &= VSIFReadL( &toc->entries[i].horizResolution, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].horizResolution);

        bOK &= VSIFReadL( &toc->entries[i].vertInterval, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].vertInterval);

        bOK &= VSIFReadL( &toc->entries[i].horizInterval, sizeof(double), 1, fp) == 1;
        CPL_MSBPTR64( &toc->entries[i].horizInterval);

        bOK &= VSIFReadL( &toc->entries[i].nVertFrames, sizeof(int), 1, fp) == 1;
        CPL_MSBPTR32( &toc->entries[i].nVertFrames );

        bOK &= VSIFReadL( &toc->entries[i].nHorizFrames, sizeof(int), 1, fp) == 1;
        CPL_MSBPTR32( &toc->entries[i].nHorizFrames );

        if( !bOK )
        {
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
            toc->entries[i].nVertFrames = 0;
            toc->entries[i].nHorizFrames = 0;
            RPFTOCFree(toc);
            return nullptr;
        }

        if( toc->entries[i].vertInterval <= 1e-10 ||
            !CPLIsFinite(toc->entries[i].vertInterval) ||
            toc->entries[i].horizInterval <= 1e-10 ||
            !CPLIsFinite(toc->entries[i].horizInterval) ||
            !(fabs(toc->entries[i].seLong) <= 360.0) ||
            !(fabs(toc->entries[i].nwLong) <= 360.0) ||
            !(fabs(toc->entries[i].nwLat) <= 90.0) ||
            !(fabs(toc->entries[i].seLat) <= 90.0) ||
            toc->entries[i].seLong < toc->entries[i].nwLong ||
            toc->entries[i].nwLat < toc->entries[i].seLat ||
            toc->entries[i].nHorizFrames == 0 ||
            toc->entries[i].nVertFrames == 0 ||
            toc->entries[i].nHorizFrames > INT_MAX / toc->entries[i].nVertFrames )
        {
            CPLError(CE_Failure, CPLE_FileIO, "Invalid TOC entry");
            toc->entries[i].nVertFrames = 0;
            toc->entries[i].nHorizFrames = 0;
            RPFTOCFree(toc);
            return nullptr;
        }

        // TODO: We could probably use another data structure, like a list,
        // instead of an array referenced by the frame coordinate...
        if( static_cast<int>(toc->entries[i].nHorizFrames *
                                  toc->entries[i].nVertFrames) >
                 atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")) )
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                     "nHorizFrames=%d x nVertFrames=%d > %d. Please raise "
                     "the value of the RPFTOC_MAX_FRAME_COUNT configuration "
                     "option to more than %d if this dataset is legitimate.",
                     toc->entries[i].nHorizFrames, toc->entries[i].nVertFrames,
                     atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")),
                     toc->entries[i].nHorizFrames * toc->entries[i].nVertFrames );
            toc->entries[i].frameEntries = nullptr;
        }
        else
        {
            toc->entries[i].frameEntries = reinterpret_cast<RPFTocFrameEntry*>(
                VSI_CALLOC_VERBOSE( toc->entries[i].nVertFrames * toc->entries[i].nHorizFrames,
                                    sizeof(RPFTocFrameEntry) ) );
        }
        if (toc->entries[i].frameEntries == nullptr)
        {
            toc->entries[i].nVertFrames = 0;
            toc->entries[i].nHorizFrames = 0;
            RPFTOCFree(toc);
            return nullptr;
        }

        CPLDebug("RPFTOC", "[%d] type=%s, compression=%s, scale=%s, zone=%s, producer=%s, nVertFrames=%d, nHorizFrames=%d",
                 i, toc->entries[i].type, toc->entries[i].compression, toc->entries[i].scale,
                 toc->entries[i].zone, toc->entries[i].producer, toc->entries[i].nVertFrames, toc->entries[i].nHorizFrames);
    }

    if( VSIFSeekL( fp, frameFileIndexSectionSubHeaderPhysIndex, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid TOC file. Unable to seek to frameFileIndexSectionSubHeaderPhysIndex at offset %d.",
                   frameFileIndexSectionSubHeaderPhysIndex );
        RPFTOCFree(toc);
        return nullptr;
    }

    /* Skip 1 byte security classification */
    bOK &= VSIFSeekL( fp, 1, SEEK_CUR ) == 0;

    unsigned int frameIndexTableOffset;
    bOK &= VSIFReadL( &frameIndexTableOffset, sizeof(frameIndexTableOffset), 1, fp) == 1;
    CPL_MSBPTR32( &frameIndexTableOffset );

    unsigned int nFrameFileIndexRecords;
    bOK &= VSIFReadL( &nFrameFileIndexRecords, sizeof(nFrameFileIndexRecords), 1, fp) == 1;
    CPL_MSBPTR32( &nFrameFileIndexRecords );

    unsigned short nFrameFilePathnameRecords;
    bOK &= VSIFReadL( &nFrameFilePathnameRecords, sizeof(nFrameFilePathnameRecords), 1, fp) == 1;
    CPL_MSBPTR16( &nFrameFilePathnameRecords );

    unsigned short frameFileIndexRecordLength;
    bOK &= VSIFReadL( &frameFileIndexRecordLength, sizeof(frameFileIndexRecordLength), 1, fp) == 1;
    CPL_MSBPTR16( &frameFileIndexRecordLength );
    if( frameFileIndexRecordLength < 3 * sizeof(short) )
    {
        CPLError(CE_Failure, CPLE_FileIO, "Invalid file");
        RPFTOCFree(toc);
        return nullptr;
    }

    if( !bOK )
    {
        CPLError(CE_Failure, CPLE_FileIO, "I/O error");
        RPFTOCFree(toc);
        return nullptr;
    }

    int newBoundaryId = 0;

    for( int i = 0; i < static_cast<int>( nFrameFileIndexRecords ); i++ )
    {
        if( VSIFSeekL( fp, frameFileIndexSubsectionPhysIndex + frameFileIndexRecordLength * i, SEEK_SET ) != 0)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                    "Invalid TOC file. Unable to seek to frameFileIndexSubsectionPhysIndex(%d) at offset %d.",
                     i, frameFileIndexSubsectionPhysIndex + frameFileIndexRecordLength * i);
            RPFTOCFree(toc);
            return nullptr;
        }

        unsigned short boundaryId;
        if( VSIFReadL( &boundaryId, sizeof(boundaryId), 1, fp) != 1 )
        {
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
            RPFTOCFree(toc);
            return nullptr;
        }
        CPL_MSBPTR16( &boundaryId );

        if (i == 0 && boundaryId == 0)
            newBoundaryId = 1;
        if (newBoundaryId == 0)
            boundaryId--;

        if (boundaryId >= toc->nEntries)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                    "Invalid TOC file. Bad boundary id (%d) for frame file index %d.",
                     boundaryId, i);
            RPFTOCFree(toc);
            return nullptr;
        }

        RPFTocEntry* entry = &toc->entries[boundaryId];
        entry->boundaryId = boundaryId;

        unsigned short frameRow;
        bOK &= VSIFReadL( &frameRow, sizeof(frameRow), 1, fp) == 1;
        CPL_MSBPTR16( &frameRow );

        unsigned short frameCol;
        bOK &= VSIFReadL( &frameCol, sizeof(frameCol), 1, fp) == 1;
        CPL_MSBPTR16( &frameCol );
        if( !bOK )
        {
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
            RPFTOCFree(toc);
            return nullptr;
        }

        if (newBoundaryId == 0)
        {
            frameRow--;
            frameCol--;
        }
        else
        {
            /* Trick so that frames are numbered north to south */
            frameRow = (unsigned short)((entry->nVertFrames-1) - frameRow);
        }

        if (frameRow >= entry->nVertFrames)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                        "Invalid TOC file. Bad row num (%d) for frame file index %d.",
                        frameRow, i);
            RPFTOCFree(toc);
            return nullptr;
        }

        if (frameCol >= entry->nHorizFrames)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                        "Invalid TOC file. Bad col num (%d) for frame file index %d.",
                        frameCol, i);
            RPFTOCFree(toc);
            return nullptr;
        }

        RPFTocFrameEntry* frameEntry
            = &entry->frameEntries[frameRow * entry->nHorizFrames + frameCol ];
        frameEntry->frameRow = frameRow;
        frameEntry->frameCol = frameCol;

        if (frameEntry->exists)
        {
            CPLError( CE_Warning, CPLE_AppDefined,
                      "Frame entry(%d,%d) for frame file index %d was already found.",
                      frameRow, frameCol, i);
            CPLFree(frameEntry->directory);
            frameEntry->directory = nullptr;
            CPLFree(frameEntry->fullFilePath);
            frameEntry->fullFilePath = nullptr;
            frameEntry->exists = 0;
        }

        unsigned int offsetFrameFilePathName;
        bOK &= VSIFReadL( &offsetFrameFilePathName, sizeof(offsetFrameFilePathName), 1, fp) == 1;
        CPL_MSBPTR32( &offsetFrameFilePathName );

        bOK &= VSIFReadL( frameEntry->filename, 1, 12, fp) == 12;
        if( !bOK )
        {
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
            RPFTOCFree(toc);
            return nullptr;
        }
        frameEntry->filename[12] = '\0';
        bOK &= strlen(frameEntry->filename) > 0;

        /* Check if the filename is an overview or legend */
        for( int j = 0; j < 12; j++ )
        {
            if (strcmp(&(frameEntry->filename[j]),".OVR") == 0 ||
                strcmp(&(frameEntry->filename[j]),".ovr") == 0 ||
                strcmp(&(frameEntry->filename[j]),".LGD") == 0 ||
                strcmp(&(frameEntry->filename[j]),".lgd") == 0)
            {
                entry->isOverviewOrLegend = TRUE;
                break;
            }
        }

        /* Extract series code */
        if (entry->seriesAbbreviation == nullptr)
        {
            const NITFSeries* series = NITFGetSeriesInfo(frameEntry->filename);
            if (series)
            {
                entry->seriesAbbreviation = series->abbreviation;
                entry->seriesName = series->name;
            }
        }

        /* Get file geo reference */
        bOK &= VSIFReadL( frameEntry->georef, 1, 6, fp) == 6;
        frameEntry->georef[6] = '\0';

        /* Go to start of pathname record */
        /* New path_off offset from start of frame file index section of TOC?? */
        /* Add pathoffset wrt frame file index table subsection (loc[3]) */
        if( !bOK || VSIFSeekL( fp, frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName, SEEK_SET ) != 0)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "Invalid TOC file. Unable to seek to "
                      "frameFileIndexSubsectionPhysIndex + "
                      "offsetFrameFilePathName(%d) at offset %d.",
                     i, frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName);
            RPFTOCFree(toc);
            return nullptr;
        }

        unsigned short pathLength;
        bOK &= VSIFReadL( &pathLength, sizeof(pathLength), 1, fp) == 1;
        CPL_MSBPTR16( &pathLength );

        /* if nFrameFileIndexRecords == 65535 and pathLength == 65535 for each record,
           this leads to 4 GB allocation... Protect against this case */
        if (!bOK || pathLength == 0 || pathLength > 256)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "Path length is invalid : %d. Probably corrupted TOC file.",
                      static_cast<int>( pathLength ) );
            RPFTOCFree(toc);
            return nullptr;
        }

        frameEntry->directory = reinterpret_cast<char *>( CPLMalloc(pathLength+1) );
        bOK &= VSIFReadL( frameEntry->directory, 1, pathLength, fp) == pathLength;
        if( !bOK )
        {
            CPLError(CE_Failure, CPLE_FileIO, "I/O error");
            RPFTOCFree(toc);
            return nullptr;
        }
        frameEntry->directory[pathLength] = 0;
        if (pathLength > 0 && frameEntry->directory[pathLength-1] == '/')
            frameEntry->directory[pathLength-1] = 0;

        if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == '/')
        {
            memmove(frameEntry->directory, frameEntry->directory+2, strlen(frameEntry->directory+2)+1);

            // Some A.TOC have subdirectory names like ".//X/" ... (#5979)
            // Check if it was not intended to be "./X/" instead.
            VSIStatBufL sStatBuf;
            if( frameEntry->directory[0] == '/' &&
                VSIStatL(CPLFormFilename(CPLGetDirname(pszFilename), frameEntry->directory+1, nullptr), &sStatBuf) == 0 &&
                VSI_ISDIR(sStatBuf.st_mode) )
            {
                memmove(frameEntry->directory, frameEntry->directory+1, strlen(frameEntry->directory+1)+1);
            }
        }

        {
            char* baseDir = CPLStrdup(CPLGetDirname(pszFilename));
            VSIStatBufL sStatBuf;
            char* subdir = nullptr;
            if (CPLIsFilenameRelative(frameEntry->directory) == FALSE)
                subdir = CPLStrdup(frameEntry->directory);
            else if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == 0)
                subdir = CPLStrdup(baseDir);
            else
                subdir = CPLStrdup(CPLFormFilename(baseDir, frameEntry->directory, nullptr));
#if !defined(_WIN32) && !defined(_WIN32_CE)
            if( VSIStatL( subdir, &sStatBuf ) != 0 && strlen(subdir) > strlen(baseDir) && subdir[strlen(baseDir)] != 0)
            {
                char* c = subdir + strlen(baseDir)+1;
                while(*c)
                {
                    if (*c >= 'A' && *c <= 'Z')
                        *c += 'a' - 'A';
                    c++;
                }
            }
#endif
            frameEntry->fullFilePath = CPLStrdup(CPLFormFilename(
                    subdir,
                    frameEntry->filename, nullptr));
            if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 )
            {
#if !defined(_WIN32) && !defined(_WIN32_CE)
                if( strlen(frameEntry->fullFilePath) > strlen(subdir) )
                {
                    char* c = frameEntry->fullFilePath + strlen(subdir)+1;
                    while(*c)
                    {
                        if (*c >= 'A' && *c <= 'Z')
                            *c += 'a' - 'A';
                        c++;
                    }
                }
                if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 )
#endif
                {
                    frameEntry->fileExists = 0;
                    CPLError( CE_Warning, CPLE_AppDefined,
                        "File %s does not exist.", frameEntry->fullFilePath );
                }
#if !defined(_WIN32) && !defined(_WIN32_CE)
                else
                {
                    frameEntry->fileExists = 1;
                }
#endif
            }
            else
            {
                frameEntry->fileExists = 1;
            }
            CPLFree(subdir);
            CPLFree(baseDir);
        }

        CPLDebug("RPFTOC", "Entry %d : %s,%s (%d, %d)", boundaryId, frameEntry->directory, frameEntry->filename, frameRow, frameCol);

        frameEntry->exists = 1;
    }

    return toc;
}
Example #3
0
RPFToc* RPFTOCReadFromBuffer(const char* pszFilename, VSILFILE* fp, const char* tocHeader)
{
    int i, j;
    unsigned int locationSectionPhysicalLocation;
    
    int nSections;
    unsigned int boundaryRectangleSectionSubHeaderPhysIndex = 0;
    unsigned int boundaryRectangleTablePhysIndex = 0;
    unsigned int frameFileIndexSectionSubHeaderPhysIndex = 0;
    unsigned int frameFileIndexSubsectionPhysIndex = 0;
    
    unsigned int boundaryRectangleTableOffset;
    unsigned short boundaryRectangleCount;
    
    unsigned int frameIndexTableOffset;
    unsigned int nFrameFileIndexRecords;
    unsigned short nFrameFilePathnameRecords;
    unsigned short frameFileIndexRecordLength;

    int newBoundaryId = 0;

    RPFToc* toc;
    
    tocHeader += 1; /* skip endian */
    tocHeader += 2; /* skip header length */
    tocHeader += 12; /* skip file name : this should be A.TOC (padded) */
    tocHeader += 1; /* skip new  */
    tocHeader += 15; /* skip standard_num  */
    tocHeader += 8; /* skip standard_date  */
    tocHeader += 1; /* skip classification  */
    tocHeader += 2; /* skip country  */
    tocHeader += 2; /* skip release  */
    
    memcpy(&locationSectionPhysicalLocation, tocHeader, sizeof(unsigned int));
    CPL_MSBPTR32(&locationSectionPhysicalLocation);
    
    if( VSIFSeekL( fp, locationSectionPhysicalLocation, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Unable to seek to locationSectionPhysicalLocation at offset %d.",
                   locationSectionPhysicalLocation );
        return NULL;
    }
    
    NITFLocation* pasLocations = NITFReadRPFLocationTable(fp, &nSections);
    
    for (i = 0; i < nSections; i++)
    {
        if (pasLocations[i].nLocId == LID_BoundaryRectangleSectionSubheader)
        {
            boundaryRectangleSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset;
        }
        else if (pasLocations[i].nLocId == LID_BoundaryRectangleTable)
        {
            boundaryRectangleTablePhysIndex = pasLocations[i].nLocOffset;
        }
        else if (pasLocations[i].nLocId == LID_FrameFileIndexSectionSubHeader)
        {
            frameFileIndexSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset;
        }
        else if (pasLocations[i].nLocId == LID_FrameFileIndexSubsection)
        {
            frameFileIndexSubsectionPhysIndex = pasLocations[i].nLocOffset;
        }
    }

    CPLFree(pasLocations);
    
    if (boundaryRectangleSectionSubHeaderPhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Can't find LID_BoundaryRectangleSectionSubheader." );
        return NULL;
    }
    if (boundaryRectangleTablePhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Can't find LID_BoundaryRectangleTable." );
        return NULL;
    }
    if (frameFileIndexSectionSubHeaderPhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Can't find LID_FrameFileIndexSectionSubHeader." );
        return NULL;
    }
    if (frameFileIndexSubsectionPhysIndex == 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Can't find LID_FrameFileIndexSubsection." );
        return NULL;
    }
    
    if( VSIFSeekL( fp, boundaryRectangleSectionSubHeaderPhysIndex, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Unable to seek to boundaryRectangleSectionSubHeaderPhysIndex at offset %d.",
                   boundaryRectangleSectionSubHeaderPhysIndex );
        return NULL;
    }
    
    VSIFReadL( &boundaryRectangleTableOffset, 1, sizeof(boundaryRectangleTableOffset), fp);
    CPL_MSBPTR32( &boundaryRectangleTableOffset );
    
    VSIFReadL( &boundaryRectangleCount, 1, sizeof(boundaryRectangleCount), fp);
    CPL_MSBPTR16( &boundaryRectangleCount );
    
    if( VSIFSeekL( fp, boundaryRectangleTablePhysIndex, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Unable to seek to boundaryRectangleTablePhysIndex at offset %d.",
                   boundaryRectangleTablePhysIndex );
        return NULL;
    }
    
    toc = (RPFToc*)CPLMalloc(sizeof(RPFToc));
    toc->nEntries = boundaryRectangleCount;
    toc->entries = (RPFTocEntry*)CPLMalloc(boundaryRectangleCount * sizeof(RPFTocEntry));
    memset(toc->entries, 0, boundaryRectangleCount * sizeof(RPFTocEntry));
    
    for(i=0;i<toc->nEntries;i++)
    {
        toc->entries[i].isOverviewOrLegend = 0;
        
        VSIFReadL( toc->entries[i].type, 1, 5, fp);
        toc->entries[i].type[5] = 0;
        RPFTOCTrim(toc->entries[i].type);
        
        VSIFReadL( toc->entries[i].compression, 1, 5, fp);
        toc->entries[i].compression[5] = 0;
        RPFTOCTrim(toc->entries[i].compression);
        
        VSIFReadL( toc->entries[i].scale, 1, 12, fp);
        toc->entries[i].scale[12] = 0;
        RPFTOCTrim(toc->entries[i].scale);
        if (toc->entries[i].scale[0] == '1' &&
            toc->entries[i].scale[1] == ':')
        {
            memmove(toc->entries[i].scale,
                    toc->entries[i].scale+2,
                    strlen(toc->entries[i].scale+2)+1);
        }
        
        VSIFReadL( toc->entries[i].zone, 1, 1, fp);
        toc->entries[i].zone[1] = 0;
        RPFTOCTrim(toc->entries[i].zone);
        
        VSIFReadL( toc->entries[i].producer, 1, 5, fp);
        toc->entries[i].producer[5] = 0;
        RPFTOCTrim(toc->entries[i].producer);

        VSIFReadL( &toc->entries[i].nwLat, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].nwLat);

        VSIFReadL( &toc->entries[i].nwLong, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].nwLong);

        VSIFReadL( &toc->entries[i].swLat, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].swLat);

        VSIFReadL( &toc->entries[i].swLong, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].swLong);

        VSIFReadL( &toc->entries[i].neLat, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].neLat);

        VSIFReadL( &toc->entries[i].neLong, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].neLong);

        VSIFReadL( &toc->entries[i].seLat, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].seLat);
        
        VSIFReadL( &toc->entries[i].seLong, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].seLong);
        
        VSIFReadL( &toc->entries[i].vertResolution, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].vertResolution);
        
        VSIFReadL( &toc->entries[i].horizResolution, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].horizResolution);
        
        VSIFReadL( &toc->entries[i].vertInterval, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].vertInterval);

        VSIFReadL( &toc->entries[i].horizInterval, 1, sizeof(double), fp);
        CPL_MSBPTR64( &toc->entries[i].horizInterval);
        
        VSIFReadL( &toc->entries[i].nVertFrames, 1, sizeof(int), fp);
        CPL_MSBPTR32( &toc->entries[i].nVertFrames );
        
        VSIFReadL( &toc->entries[i].nHorizFrames, 1, sizeof(int), fp);
        CPL_MSBPTR32( &toc->entries[i].nHorizFrames );
        
        toc->entries[i].frameEntries = (RPFTocFrameEntry*)
                VSIMalloc3(toc->entries[i].nVertFrames, toc->entries[i].nHorizFrames, sizeof(RPFTocFrameEntry));
        if (toc->entries[i].frameEntries == NULL)
        {
            CPLError( CE_Failure, CPLE_OutOfMemory,
                      "RPFTOCReadFromBuffer : Out of memory. Probably due to corrupted TOC file.");
            RPFTOCFree(toc);
            return NULL;
        }
        memset(toc->entries[i].frameEntries, 0,
               toc->entries[i].nVertFrames * toc->entries[i].nHorizFrames * sizeof(RPFTocFrameEntry));
        
        CPLDebug("RPFTOC", "[%d] type=%s, compression=%s, scale=%s, zone=%s, producer=%s, nVertFrames=%d, nHorizFrames=%d",
                 i, toc->entries[i].type, toc->entries[i].compression, toc->entries[i].scale,
                 toc->entries[i].zone, toc->entries[i].producer, toc->entries[i].nVertFrames, toc->entries[i].nHorizFrames);
    }
    
    if( VSIFSeekL( fp, frameFileIndexSectionSubHeaderPhysIndex, SEEK_SET ) != 0)
    {
        CPLError( CE_Failure, CPLE_NotSupported, 
                  "Invalid TOC file. Unable to seek to frameFileIndexSectionSubHeaderPhysIndex at offset %d.",
                   frameFileIndexSectionSubHeaderPhysIndex );
        RPFTOCFree(toc);
        return NULL;
    }
    
    /* Skip 1 byte security classification */
    VSIFSeekL( fp, 1, SEEK_CUR );
    
    VSIFReadL( &frameIndexTableOffset, 1, sizeof(frameIndexTableOffset), fp);
    CPL_MSBPTR32( &frameIndexTableOffset );
    
    VSIFReadL( &nFrameFileIndexRecords, 1, sizeof(nFrameFileIndexRecords), fp);
    CPL_MSBPTR32( &nFrameFileIndexRecords );
    
    VSIFReadL( &nFrameFilePathnameRecords, 1, sizeof(nFrameFilePathnameRecords), fp);
    CPL_MSBPTR16( &nFrameFilePathnameRecords );
    
    VSIFReadL( &frameFileIndexRecordLength, 1, sizeof(frameFileIndexRecordLength), fp);
    CPL_MSBPTR16( &frameFileIndexRecordLength );
    
    for (i=0;i<(int)nFrameFileIndexRecords;i++)
    {
        RPFTocEntry* entry;
        RPFTocFrameEntry* frameEntry;
        unsigned short boundaryId, frameRow, frameCol;
        unsigned int offsetFrameFilePathName;
        unsigned short pathLength;
        
        if( VSIFSeekL( fp, frameFileIndexSubsectionPhysIndex + frameFileIndexRecordLength * i, SEEK_SET ) != 0)
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                    "Invalid TOC file. Unable to seek to frameFileIndexSubsectionPhysIndex(%d) at offset %d.",
                     i, frameFileIndexSubsectionPhysIndex + frameFileIndexRecordLength * i);
            RPFTOCFree(toc);
            return NULL;
        }

        VSIFReadL( &boundaryId, 1, sizeof(boundaryId), fp);
        CPL_MSBPTR16( &boundaryId );
        
        if (i == 0 && boundaryId == 0)
            newBoundaryId = 1;
        if (newBoundaryId == 0)
            boundaryId--;
        
        if (boundaryId >= toc->nEntries)
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                    "Invalid TOC file. Bad boundary id (%d) for frame file index %d.",
                     boundaryId, i);
            RPFTOCFree(toc);
            return NULL;
        }
        
        entry = &toc->entries[boundaryId];
        entry->boundaryId = boundaryId;
        
        VSIFReadL( &frameRow, 1, sizeof(frameRow), fp);
        CPL_MSBPTR16( &frameRow );
        
        VSIFReadL( &frameCol, 1, sizeof(frameCol), fp);
        CPL_MSBPTR16( &frameCol );


        if (newBoundaryId == 0)
        {
            frameRow--;
            frameCol--;
        }
        else
        {
            /* Trick so that frames are numbered north to south */
            frameRow = (unsigned short)((entry->nVertFrames-1) - frameRow);
        }
   
        if (frameRow >= entry->nVertFrames)
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                        "Invalid TOC file. Bad row num (%d) for frame file index %d.",
                        frameRow, i);
            RPFTOCFree(toc);
            return NULL;
        }
        
        if (frameCol >= entry->nHorizFrames)
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                        "Invalid TOC file. Bad col num (%d) for frame file index %d.",
                        frameCol, i);
            RPFTOCFree(toc);
            return NULL;
        }

        frameEntry = &entry->frameEntries[frameRow * entry->nHorizFrames + frameCol ];
        frameEntry->frameRow = frameRow;
        frameEntry->frameCol = frameCol;

        if (frameEntry->exists)
        {
            CPLError( CE_Warning, CPLE_AppDefined, 
                      "Frame entry(%d,%d) for frame file index %d was already found.",
                      frameRow, frameCol, i);
            CPLFree(frameEntry->directory);
            frameEntry->directory = NULL;
            CPLFree(frameEntry->fullFilePath);
            frameEntry->fullFilePath = NULL;
            frameEntry->exists = 0;
        }
        
        VSIFReadL( &offsetFrameFilePathName, 1, sizeof(offsetFrameFilePathName), fp);
        CPL_MSBPTR32( &offsetFrameFilePathName );
        

        VSIFReadL( frameEntry->filename, 1, 12, fp);
        frameEntry->filename[12] = '\0';

        /* Check if the filename is an overview or legend */
        for (j=0;j<12;j++)
        {
            if (strcmp(&(frameEntry->filename[j]),".OVR") == 0 ||
                strcmp(&(frameEntry->filename[j]),".ovr") == 0 ||
                strcmp(&(frameEntry->filename[j]),".LGD") == 0 ||
                strcmp(&(frameEntry->filename[j]),".lgd") == 0)
            {
                entry->isOverviewOrLegend = TRUE;
                break;
            }
        }
        
        /* Extract series code */
        if (entry->seriesAbbreviation == NULL)
        {
            const NITFSeries* series = NITFGetSeriesInfo(frameEntry->filename);
            if (series)
            {
                entry->seriesAbbreviation = series->abbreviation;
                entry->seriesName = series->name;
            }
        }

        /* Get file geo reference */
        VSIFReadL( frameEntry->georef, 1, 6, fp);
        frameEntry->georef[6] = '\0';

        /* Go to start of pathname record */
        /* New path_off offset from start of frame file index section of TOC?? */
        /* Add pathoffset wrt frame file index table subsection (loc[3]) */
        if( VSIFSeekL( fp, frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName, SEEK_SET ) != 0)
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                    "Invalid TOC file. Unable to seek to frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName(%d) at offset %d.",
                     i, frameFileIndexSubsectionPhysIndex + offsetFrameFilePathName);
            RPFTOCFree(toc);
            return NULL;
        }

        VSIFReadL( &pathLength, 1, sizeof(pathLength), fp);
        CPL_MSBPTR16( &pathLength );
        
        /* if nFrameFileIndexRecords == 65535 and pathLength == 65535 for each record,
           this leads to 4 GB allocation... Protect against this case */
        if (pathLength > 256)
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "Path length is big : %d. Probably corrupted TOC file.", (int)pathLength);
            RPFTOCFree(toc);
            return NULL;
        }
        
        frameEntry->directory = (char *)CPLMalloc(pathLength+1);
        VSIFReadL( frameEntry->directory, 1, pathLength, fp);
        frameEntry->directory[pathLength] = 0;
        if (pathLength > 0 && frameEntry->directory[pathLength-1] == '/')
            frameEntry->directory[pathLength-1] = 0;
        
        if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == '/')
            memmove(frameEntry->directory, frameEntry->directory+2, strlen(frameEntry->directory+2)+1);
        
        {
            char* baseDir = CPLStrdup(CPLGetDirname(pszFilename));
            VSIStatBufL sStatBuf;
            char* subdir;
            if (CPLIsFilenameRelative(frameEntry->directory) == FALSE)
                subdir = CPLStrdup(frameEntry->directory);
            else if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == 0)
                subdir = CPLStrdup(baseDir);
            else
                subdir = CPLStrdup(CPLFormFilename(baseDir, frameEntry->directory, NULL));
#if !defined(_WIN32) && !defined(_WIN32_CE)
            if( VSIStatL( subdir, &sStatBuf ) != 0 && subdir[strlen(baseDir)] != 0)
            {
                char* c = subdir + strlen(baseDir)+1;
                while(*c)
                {
                    if (*c >= 'A' && *c <= 'Z')
                        *c += 'a' - 'A';
                    c++;
                }
            }
#endif
            frameEntry->fullFilePath = CPLStrdup(CPLFormFilename(
                    subdir,
                    frameEntry->filename, NULL));
            if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 )
            {
#if !defined(_WIN32) && !defined(_WIN32_CE)
                char* c = frameEntry->fullFilePath + strlen(subdir)+1;
                while(*c)
                {
                    if (*c >= 'A' && *c <= 'Z')
                        *c += 'a' - 'A';
                    c++;
                }
                if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 )
#endif
                {
                    frameEntry->fileExists = 0;
                    CPLError( CE_Warning, CPLE_AppDefined, 
                        "File %s does not exist.", frameEntry->fullFilePath );
                }
#if !defined(_WIN32) && !defined(_WIN32_CE)
                else
                {
                    frameEntry->fileExists = 1;
                }
#endif
            }
            else
            {
                frameEntry->fileExists = 1;
            }
            CPLFree(subdir);
            CPLFree(baseDir);
        }

        CPLDebug("RPFTOC", "Entry %d : %s,%s (%d, %d)", boundaryId, frameEntry->directory, frameEntry->filename, frameRow, frameCol);

        frameEntry->exists = 1;
    }
    
    return toc;
}