LCOV - code coverage report
Current view: top level - gcore - gdaljp2box.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 169 216 78.2 %
Date: 2025-01-18 12:42:00 Functions: 25 26 96.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  GDALJP2Box Implementation - Low level JP2 box reader.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "gdaljp2metadata.h"
      16             : 
      17             : #include <cstddef>
      18             : #include <cstdio>
      19             : #include <cstring>
      20             : #if HAVE_FCNTL_H
      21             : #include <fcntl.h>
      22             : #endif
      23             : 
      24             : #include <algorithm>
      25             : 
      26             : #include "cpl_conv.h"
      27             : #include "cpl_error.h"
      28             : #include "cpl_string.h"
      29             : #include "cpl_vsi.h"
      30             : 
      31             : /*! @cond Doxygen_Suppress */
      32             : 
      33             : /************************************************************************/
      34             : /*                             GDALJP2Box()                             */
      35             : /************************************************************************/
      36             : 
      37             : // GDALJP2Box does *not* take ownership of fpIn
      38        7775 : GDALJP2Box::GDALJP2Box(VSILFILE *fpIn) : fpVSIL(fpIn)
      39             : {
      40        7775 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                            ~GDALJP2Box()                             */
      44             : /************************************************************************/
      45             : 
      46       15550 : GDALJP2Box::~GDALJP2Box()
      47             : 
      48             : {
      49             :     // Do not close fpVSIL. Ownership remains to the caller of GDALJP2Box
      50             :     // constructor
      51        7775 :     CPLFree(pabyData);
      52        7775 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                             SetOffset()                              */
      56             : /************************************************************************/
      57             : 
      58       20174 : int GDALJP2Box::SetOffset(GIntBig nNewOffset)
      59             : 
      60             : {
      61       20174 :     szBoxType[0] = '\0';
      62       20174 :     return VSIFSeekL(fpVSIL, nNewOffset, SEEK_SET) == 0;
      63             : }
      64             : 
      65             : /************************************************************************/
      66             : /*                             ReadFirst()                              */
      67             : /************************************************************************/
      68             : 
      69        2626 : int GDALJP2Box::ReadFirst()
      70             : 
      71             : {
      72        2626 :     return SetOffset(0) && ReadBox();
      73             : }
      74             : 
      75             : /************************************************************************/
      76             : /*                              ReadNext()                              */
      77             : /************************************************************************/
      78             : 
      79       15246 : int GDALJP2Box::ReadNext()
      80             : 
      81             : {
      82       15246 :     return SetOffset(nBoxOffset + nBoxLength) && ReadBox();
      83             : }
      84             : 
      85             : /************************************************************************/
      86             : /*                           ReadFirstChild()                           */
      87             : /************************************************************************/
      88             : 
      89        2343 : int GDALJP2Box::ReadFirstChild(GDALJP2Box *poSuperBox)
      90             : 
      91             : {
      92        2343 :     if (poSuperBox == nullptr)
      93          41 :         return ReadFirst();
      94             : 
      95        2302 :     szBoxType[0] = '\0';
      96        2302 :     if (!poSuperBox->IsSuperBox())
      97           0 :         return FALSE;
      98             : 
      99        2302 :     return SetOffset(poSuperBox->nDataOffset) && ReadBox();
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                           ReadNextChild()                            */
     104             : /************************************************************************/
     105             : 
     106        4658 : int GDALJP2Box::ReadNextChild(GDALJP2Box *poSuperBox)
     107             : 
     108             : {
     109        4658 :     if (poSuperBox == nullptr)
     110         210 :         return ReadNext();
     111             : 
     112        4448 :     if (!ReadNext())
     113           0 :         return FALSE;
     114             : 
     115        4448 :     if (nBoxOffset >= poSuperBox->nBoxOffset + poSuperBox->nBoxLength)
     116             :     {
     117        2045 :         szBoxType[0] = '\0';
     118        2045 :         return FALSE;
     119             :     }
     120             : 
     121        2403 :     return TRUE;
     122             : }
     123             : 
     124             : /************************************************************************/
     125             : /*                              ReadBox()                               */
     126             : /************************************************************************/
     127             : 
     128       20174 : int GDALJP2Box::ReadBox()
     129             : 
     130             : {
     131       20174 :     GUInt32 nLBox = 0;
     132       20174 :     GUInt32 nTBox = 0;
     133             : 
     134       20174 :     nBoxOffset = VSIFTellL(fpVSIL);
     135             : 
     136       38575 :     if (VSIFReadL(&nLBox, 4, 1, fpVSIL) != 1 ||
     137       18401 :         VSIFReadL(&nTBox, 4, 1, fpVSIL) != 1)
     138             :     {
     139        1774 :         return FALSE;
     140             :     }
     141             : 
     142       18400 :     memcpy(szBoxType, &nTBox, 4);
     143       18400 :     szBoxType[4] = '\0';
     144             : 
     145       18400 :     nLBox = CPL_MSBWORD32(nLBox);
     146             : 
     147       18400 :     if (nLBox != 1)
     148             :     {
     149       18395 :         nBoxLength = nLBox;
     150       18395 :         nDataOffset = nBoxOffset + 8;
     151             :     }
     152             :     else
     153             :     {
     154           5 :         GByte abyXLBox[8] = {0};
     155           5 :         if (VSIFReadL(abyXLBox, 8, 1, fpVSIL) != 1)
     156           0 :             return FALSE;
     157             : 
     158           5 :         CPL_MSBPTR64(abyXLBox);
     159           5 :         memcpy(&nBoxLength, abyXLBox, 8);
     160             : 
     161           5 :         if (nBoxLength < 0)
     162             :         {
     163           0 :             CPLDebug("GDALJP2", "Invalid length for box %s", szBoxType);
     164           0 :             return FALSE;
     165             :         }
     166           5 :         nDataOffset = nBoxOffset + 16;
     167             :     }
     168             : 
     169       18400 :     if (nBoxLength == 0 && m_bAllowGetFileSize)
     170             :     {
     171         266 :         if (VSIFSeekL(fpVSIL, 0, SEEK_END) != 0)
     172           0 :             return FALSE;
     173         266 :         nBoxLength = VSIFTellL(fpVSIL) - nBoxOffset;
     174         266 :         if (VSIFSeekL(fpVSIL, nDataOffset, SEEK_SET) != 0)
     175           0 :             return FALSE;
     176             :     }
     177             : 
     178       18400 :     if (EQUAL(szBoxType, "uuid"))
     179             :     {
     180        2779 :         if (VSIFReadL(abyUUID, 16, 1, fpVSIL) != 1)
     181           0 :             return FALSE;
     182        2779 :         nDataOffset += 16;
     183             :     }
     184             : 
     185       18400 :     if (m_bAllowGetFileSize && GetDataLength() < 0)
     186             :     {
     187           0 :         CPLDebug("GDALJP2", "Invalid length for box %s", szBoxType);
     188           0 :         return FALSE;
     189             :     }
     190             : 
     191       18400 :     return TRUE;
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /*                             IsSuperBox()                             */
     196             : /************************************************************************/
     197             : 
     198        2703 : int GDALJP2Box::IsSuperBox()
     199             : 
     200             : {
     201        4599 :     if (EQUAL(GetType(), "asoc") || EQUAL(GetType(), "jp2h") ||
     202        4599 :         EQUAL(GetType(), "res ") || EQUAL(GetType(), "jumb"))
     203        2382 :         return TRUE;
     204             : 
     205         321 :     return FALSE;
     206             : }
     207             : 
     208             : /************************************************************************/
     209             : /*                            ReadBoxData()                             */
     210             : /************************************************************************/
     211             : 
     212        2810 : GByte *GDALJP2Box::ReadBoxData()
     213             : 
     214             : {
     215        2810 :     GIntBig nDataLength = GetDataLength();
     216        2810 :     if (nDataLength > 100 * 1024 * 1024)
     217             :     {
     218           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     219             :                  "Too big box : " CPL_FRMT_GIB " bytes", nDataLength);
     220           0 :         return nullptr;
     221             :     }
     222             : 
     223        2810 :     if (VSIFSeekL(fpVSIL, nDataOffset, SEEK_SET) != 0)
     224           0 :         return nullptr;
     225             : 
     226             :     char *pszData = static_cast<char *>(
     227        2810 :         VSI_MALLOC_VERBOSE(static_cast<int>(nDataLength) + 1));
     228        2810 :     if (pszData == nullptr)
     229           0 :         return nullptr;
     230             : 
     231        2810 :     if (static_cast<GIntBig>(VSIFReadL(
     232        2810 :             pszData, 1, static_cast<int>(nDataLength), fpVSIL)) != nDataLength)
     233             :     {
     234           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot read box content");
     235           0 :         CPLFree(pszData);
     236           0 :         return nullptr;
     237             :     }
     238             : 
     239        2810 :     pszData[nDataLength] = '\0';
     240             : 
     241        2810 :     return reinterpret_cast<GByte *>(pszData);
     242             : }
     243             : 
     244             : /************************************************************************/
     245             : /*                           GetDataLength()                            */
     246             : /************************************************************************/
     247             : 
     248       39948 : GIntBig GDALJP2Box::GetDataLength() const
     249             : {
     250       39948 :     return nBoxLength - (nDataOffset - nBoxOffset);
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                            DumpReadable()                            */
     255             : /************************************************************************/
     256             : 
     257           0 : int GDALJP2Box::DumpReadable(FILE *fpOut, int nIndentLevel)
     258             : 
     259             : {
     260           0 :     if (fpOut == nullptr)
     261           0 :         fpOut = stdout;
     262             : 
     263           0 :     for (int i = 0; i < nIndentLevel; ++i)
     264           0 :         fprintf(fpOut, "  ");
     265             : 
     266             :     char szBuffer[128];
     267           0 :     CPLsnprintf(szBuffer, sizeof(szBuffer),
     268             :                 "  Type=%s, Offset=" CPL_FRMT_GIB "/" CPL_FRMT_GIB
     269             :                 ", Data Size=" CPL_FRMT_GIB,
     270           0 :                 szBoxType, nBoxOffset, nDataOffset, GetDataLength());
     271           0 :     fprintf(fpOut, "%s", szBuffer);
     272             : 
     273           0 :     if (IsSuperBox())
     274             :     {
     275           0 :         fprintf(fpOut, " (super)");
     276             :     }
     277             : 
     278           0 :     fprintf(fpOut, "\n");
     279             : 
     280           0 :     if (IsSuperBox())
     281             :     {
     282           0 :         GDALJP2Box oSubBox(GetFILE());
     283             : 
     284           0 :         for (oSubBox.ReadFirstChild(this); strlen(oSubBox.GetType()) > 0;
     285           0 :              oSubBox.ReadNextChild(this))
     286             :         {
     287           0 :             oSubBox.DumpReadable(fpOut, nIndentLevel + 1);
     288             :         }
     289             :     }
     290             : 
     291           0 :     if (EQUAL(GetType(), "uuid"))
     292             :     {
     293           0 :         char *pszHex = CPLBinaryToHex(16, GetUUID());
     294           0 :         for (int i = 0; i < nIndentLevel; ++i)
     295           0 :             fprintf(fpOut, "  ");
     296             : 
     297           0 :         fprintf(fpOut, "    UUID=%s", pszHex);
     298             : 
     299           0 :         if (EQUAL(pszHex, "B14BF8BD083D4B43A5AE8CD7D5A6CE03"))
     300           0 :             fprintf(fpOut, " (GeoTIFF)");
     301           0 :         if (EQUAL(pszHex, "96A9F1F1DC98402DA7AED68E34451809"))
     302           0 :             fprintf(fpOut, " (MSI Worldfile)");
     303           0 :         if (EQUAL(pszHex, "BE7ACFCB97A942E89C71999491E3AFAC"))
     304           0 :             fprintf(fpOut, " (XMP)");
     305           0 :         CPLFree(pszHex);
     306             : 
     307           0 :         fprintf(fpOut, "\n");
     308             :     }
     309             : 
     310           0 :     return 0;
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                              SetType()                               */
     315             : /************************************************************************/
     316             : 
     317        2006 : void GDALJP2Box::SetType(const char *pszType)
     318             : 
     319             : {
     320        2006 :     CPLAssert(strlen(pszType) == 4);
     321             : 
     322        2006 :     memcpy(szBoxType, pszType, 4);
     323        2006 :     szBoxType[4] = '\0';
     324        2006 : }
     325             : 
     326             : /************************************************************************/
     327             : /*                          GetWritableBoxData()                        */
     328             : /************************************************************************/
     329             : 
     330          31 : GByte *GDALJP2Box::GetWritableBoxData() const
     331             : {
     332             :     GByte *pabyRet =
     333          31 :         static_cast<GByte *>(CPLMalloc(static_cast<GUInt32>(nBoxLength)));
     334          31 :     const GUInt32 nLBox = CPL_MSBWORD32(static_cast<GUInt32>(nBoxLength));
     335          31 :     memcpy(pabyRet, &nLBox, sizeof(GUInt32));
     336          31 :     memcpy(pabyRet + 4, szBoxType, 4);
     337          31 :     memcpy(pabyRet + 8, pabyData, static_cast<GUInt32>(nBoxLength) - 8);
     338          31 :     return pabyRet;
     339             : }
     340             : 
     341             : /************************************************************************/
     342             : /*                          SetWritableData()                           */
     343             : /************************************************************************/
     344             : 
     345         774 : void GDALJP2Box::SetWritableData(int nLength, const GByte *pabyDataIn)
     346             : 
     347             : {
     348         774 :     CPLFree(pabyData);
     349             : 
     350         774 :     pabyData = static_cast<GByte *>(CPLMalloc(nLength));
     351         774 :     memcpy(pabyData, pabyDataIn, nLength);
     352             : 
     353         774 :     nBoxOffset = -9;  // Virtual offsets for data length computation.
     354         774 :     nDataOffset = -1;
     355             : 
     356         774 :     nBoxLength = 8 + nLength;
     357         774 : }
     358             : 
     359             : /************************************************************************/
     360             : /*                          AppendWritableData()                        */
     361             : /************************************************************************/
     362             : 
     363        4745 : void GDALJP2Box::AppendWritableData(int nLength, const void *pabyDataIn)
     364             : 
     365             : {
     366        4745 :     if (pabyData == nullptr)
     367             :     {
     368        1227 :         nBoxOffset = -9;  // Virtual offsets for data length computation.
     369        1227 :         nDataOffset = -1;
     370        1227 :         nBoxLength = 8;
     371             :     }
     372             : 
     373        4745 :     pabyData = static_cast<GByte *>(
     374        4745 :         CPLRealloc(pabyData, static_cast<size_t>(GetDataLength() + nLength)));
     375        4745 :     memcpy(pabyData + GetDataLength(), pabyDataIn, nLength);
     376             : 
     377        4745 :     nBoxLength += nLength;
     378        4745 : }
     379             : 
     380             : /************************************************************************/
     381             : /*                              AppendUInt32()                          */
     382             : /************************************************************************/
     383             : 
     384         872 : void GDALJP2Box::AppendUInt32(GUInt32 nVal)
     385             : {
     386         872 :     CPL_MSBPTR32(&nVal);
     387         872 :     AppendWritableData(4, &nVal);
     388         872 : }
     389             : 
     390             : /************************************************************************/
     391             : /*                              AppendUInt16()                          */
     392             : /************************************************************************/
     393             : 
     394         619 : void GDALJP2Box::AppendUInt16(GUInt16 nVal)
     395             : {
     396         619 :     CPL_MSBPTR16(&nVal);
     397         619 :     AppendWritableData(2, &nVal);
     398         619 : }
     399             : 
     400             : /************************************************************************/
     401             : /*                              AppendUInt8()                           */
     402             : /************************************************************************/
     403             : 
     404        2009 : void GDALJP2Box::AppendUInt8(GByte nVal)
     405             : {
     406        2009 :     AppendWritableData(1, &nVal);
     407        2009 : }
     408             : 
     409             : /************************************************************************/
     410             : /*                           CreateUUIDBox()                            */
     411             : /************************************************************************/
     412             : 
     413         228 : GDALJP2Box *GDALJP2Box::CreateUUIDBox(const GByte *pabyUUID, int nDataSize,
     414             :                                       const GByte *pabyDataIn)
     415             : 
     416             : {
     417         228 :     GDALJP2Box *const poBox = new GDALJP2Box();
     418         228 :     poBox->SetType("uuid");
     419             : 
     420         228 :     poBox->AppendWritableData(16, pabyUUID);
     421         228 :     poBox->AppendWritableData(nDataSize, pabyDataIn);
     422             : 
     423         228 :     return poBox;
     424             : }
     425             : 
     426             : /************************************************************************/
     427             : /*                           CreateAsocBox()                            */
     428             : /************************************************************************/
     429             : 
     430         200 : GDALJP2Box *GDALJP2Box::CreateAsocBox(int nCount,
     431             :                                       const GDALJP2Box *const *papoBoxes)
     432             : {
     433         200 :     return CreateSuperBox("asoc", nCount, papoBoxes);
     434             : }
     435             : 
     436             : /************************************************************************/
     437             : /*                           CreateAsocBox()                            */
     438             : /************************************************************************/
     439             : 
     440         457 : GDALJP2Box *GDALJP2Box::CreateSuperBox(const char *pszType, int nCount,
     441             :                                        const GDALJP2Box *const *papoBoxes)
     442             : {
     443         457 :     int nDataSize = 0;
     444             : 
     445             :     /* -------------------------------------------------------------------- */
     446             :     /*      Compute size of data area of asoc box.                          */
     447             :     /* -------------------------------------------------------------------- */
     448        1418 :     for (int iBox = 0; iBox < nCount; ++iBox)
     449         961 :         nDataSize += 8 + static_cast<int>(papoBoxes[iBox]->GetDataLength());
     450             : 
     451         457 :     GByte *pabyNext = static_cast<GByte *>(CPLMalloc(nDataSize));
     452         457 :     GByte *pabyCompositeData = pabyNext;
     453             : 
     454             :     /* -------------------------------------------------------------------- */
     455             :     /*      Copy subboxes headers and data into buffer.                     */
     456             :     /* -------------------------------------------------------------------- */
     457        1418 :     for (int iBox = 0; iBox < nCount; ++iBox)
     458             :     {
     459         961 :         GUInt32 nLBox =
     460         961 :             CPL_MSBWORD32(static_cast<GUInt32>(papoBoxes[iBox]->nBoxLength));
     461         961 :         memcpy(pabyNext, &nLBox, 4);
     462         961 :         pabyNext += 4;
     463             : 
     464         961 :         memcpy(pabyNext, papoBoxes[iBox]->szBoxType, 4);
     465         961 :         pabyNext += 4;
     466             : 
     467         961 :         memcpy(pabyNext, papoBoxes[iBox]->pabyData,
     468         961 :                static_cast<int>(papoBoxes[iBox]->GetDataLength()));
     469         961 :         pabyNext += papoBoxes[iBox]->GetDataLength();
     470             :     }
     471             : 
     472             :     /* -------------------------------------------------------------------- */
     473             :     /*      Create asoc box.                                                */
     474             :     /* -------------------------------------------------------------------- */
     475         457 :     GDALJP2Box *const poAsoc = new GDALJP2Box();
     476             : 
     477         457 :     poAsoc->SetType(pszType);
     478         457 :     poAsoc->SetWritableData(nDataSize, pabyCompositeData);
     479             : 
     480         457 :     CPLFree(pabyCompositeData);
     481             : 
     482         457 :     return poAsoc;
     483             : }
     484             : 
     485             : /************************************************************************/
     486             : /*                            CreateLblBox()                            */
     487             : /************************************************************************/
     488             : 
     489          87 : GDALJP2Box *GDALJP2Box::CreateLblBox(const char *pszLabel)
     490             : 
     491             : {
     492          87 :     GDALJP2Box *const poBox = new GDALJP2Box();
     493          87 :     poBox->SetType("lbl ");
     494          87 :     poBox->SetWritableData(static_cast<int>(strlen(pszLabel) + 1),
     495             :                            reinterpret_cast<const GByte *>(pszLabel));
     496             : 
     497          87 :     return poBox;
     498             : }
     499             : 
     500             : /************************************************************************/
     501             : /*                       CreateLabelledXMLAssoc()                       */
     502             : /************************************************************************/
     503             : 
     504         108 : GDALJP2Box *GDALJP2Box::CreateLabelledXMLAssoc(const char *pszLabel,
     505             :                                                const char *pszXML)
     506             : 
     507             : {
     508         216 :     GDALJP2Box oLabel;
     509         108 :     oLabel.SetType("lbl ");
     510         108 :     oLabel.SetWritableData(static_cast<int>(strlen(pszLabel) + 1),
     511             :                            reinterpret_cast<const GByte *>(pszLabel));
     512             : 
     513         216 :     GDALJP2Box oXML;
     514         108 :     oXML.SetType("xml ");
     515         108 :     oXML.SetWritableData(static_cast<int>(strlen(pszXML) + 1),
     516             :                          reinterpret_cast<const GByte *>(pszXML));
     517             : 
     518         108 :     GDALJP2Box *aoList[2] = {&oLabel, &oXML};
     519             : 
     520         216 :     return CreateAsocBox(2, aoList);
     521             : }
     522             : 
     523             : /************************************************************************/
     524             : /*                    CreateJUMBFDescriptionBox()                       */
     525             : /************************************************************************/
     526             : 
     527          39 : GDALJP2Box *GDALJP2Box::CreateJUMBFDescriptionBox(const GByte *pabyUUIDType,
     528             :                                                   const char *pszLabel)
     529             : 
     530             : {
     531          39 :     GDALJP2Box *const poBox = new GDALJP2Box();
     532          39 :     poBox->SetType("jumd");
     533             : 
     534          39 :     poBox->AppendWritableData(16, pabyUUIDType);
     535          39 :     poBox->AppendUInt8(3);  // requestable field
     536          39 :     const size_t nLabelLen = strlen(pszLabel) + 1;
     537          39 :     poBox->AppendWritableData(static_cast<int>(nLabelLen), pszLabel);
     538             : 
     539          39 :     return poBox;
     540             : }
     541             : 
     542             : /************************************************************************/
     543             : /*                         CreateJUMBFBox()                             */
     544             : /************************************************************************/
     545             : 
     546          39 : GDALJP2Box *GDALJP2Box::CreateJUMBFBox(const GDALJP2Box *poJUMBFDescriptionBox,
     547             :                                        int nCount,
     548             :                                        const GDALJP2Box *const *papoBoxes)
     549             : {
     550          78 :     std::vector<const GDALJP2Box *> apoBoxes;
     551          39 :     apoBoxes.push_back(poJUMBFDescriptionBox);
     552          39 :     apoBoxes.insert(apoBoxes.end(), papoBoxes, papoBoxes + nCount);
     553          39 :     return CreateSuperBox("jumb", static_cast<int>(apoBoxes.size()),
     554         117 :                           apoBoxes.data());
     555             : }
     556             : 
     557             : /*! @endcond */

Generated by: LCOV version 1.14