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: 2024-05-04 12:52:34 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_port.h"
      31             : #include "gdaljp2metadata.h"
      32             : 
      33             : #include <cstddef>
      34             : #include <cstdio>
      35             : #include <cstring>
      36             : #if HAVE_FCNTL_H
      37             : #include <fcntl.h>
      38             : #endif
      39             : 
      40             : #include <algorithm>
      41             : 
      42             : #include "cpl_conv.h"
      43             : #include "cpl_error.h"
      44             : #include "cpl_string.h"
      45             : #include "cpl_vsi.h"
      46             : 
      47             : /*! @cond Doxygen_Suppress */
      48             : 
      49             : /************************************************************************/
      50             : /*                             GDALJP2Box()                             */
      51             : /************************************************************************/
      52             : 
      53             : // GDALJP2Box does *not* take ownership of fpIn
      54        7555 : GDALJP2Box::GDALJP2Box(VSILFILE *fpIn) : fpVSIL(fpIn)
      55             : {
      56        7555 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                            ~GDALJP2Box()                             */
      60             : /************************************************************************/
      61             : 
      62       15110 : GDALJP2Box::~GDALJP2Box()
      63             : 
      64             : {
      65             :     // Do not close fpVSIL. Ownership remains to the caller of GDALJP2Box
      66             :     // constructor
      67        7555 :     CPLFree(pabyData);
      68        7555 : }
      69             : 
      70             : /************************************************************************/
      71             : /*                             SetOffset()                              */
      72             : /************************************************************************/
      73             : 
      74       19892 : int GDALJP2Box::SetOffset(GIntBig nNewOffset)
      75             : 
      76             : {
      77       19892 :     szBoxType[0] = '\0';
      78       19892 :     return VSIFSeekL(fpVSIL, nNewOffset, SEEK_SET) == 0;
      79             : }
      80             : 
      81             : /************************************************************************/
      82             : /*                             ReadFirst()                              */
      83             : /************************************************************************/
      84             : 
      85        2443 : int GDALJP2Box::ReadFirst()
      86             : 
      87             : {
      88        2443 :     return SetOffset(0) && ReadBox();
      89             : }
      90             : 
      91             : /************************************************************************/
      92             : /*                              ReadNext()                              */
      93             : /************************************************************************/
      94             : 
      95       15165 : int GDALJP2Box::ReadNext()
      96             : 
      97             : {
      98       15165 :     return SetOffset(nBoxOffset + nBoxLength) && ReadBox();
      99             : }
     100             : 
     101             : /************************************************************************/
     102             : /*                           ReadFirstChild()                           */
     103             : /************************************************************************/
     104             : 
     105        2325 : int GDALJP2Box::ReadFirstChild(GDALJP2Box *poSuperBox)
     106             : 
     107             : {
     108        2325 :     if (poSuperBox == nullptr)
     109          41 :         return ReadFirst();
     110             : 
     111        2284 :     szBoxType[0] = '\0';
     112        2284 :     if (!poSuperBox->IsSuperBox())
     113           0 :         return FALSE;
     114             : 
     115        2284 :     return SetOffset(poSuperBox->nDataOffset) && ReadBox();
     116             : }
     117             : 
     118             : /************************************************************************/
     119             : /*                           ReadNextChild()                            */
     120             : /************************************************************************/
     121             : 
     122        4628 : int GDALJP2Box::ReadNextChild(GDALJP2Box *poSuperBox)
     123             : 
     124             : {
     125        4628 :     if (poSuperBox == nullptr)
     126         210 :         return ReadNext();
     127             : 
     128        4418 :     if (!ReadNext())
     129           0 :         return FALSE;
     130             : 
     131        4418 :     if (nBoxOffset >= poSuperBox->nBoxOffset + poSuperBox->nBoxLength)
     132             :     {
     133        2030 :         szBoxType[0] = '\0';
     134        2030 :         return FALSE;
     135             :     }
     136             : 
     137        2388 :     return TRUE;
     138             : }
     139             : 
     140             : /************************************************************************/
     141             : /*                              ReadBox()                               */
     142             : /************************************************************************/
     143             : 
     144       19892 : int GDALJP2Box::ReadBox()
     145             : 
     146             : {
     147       19892 :     GUInt32 nLBox = 0;
     148       19892 :     GUInt32 nTBox = 0;
     149             : 
     150       19892 :     nBoxOffset = VSIFTellL(fpVSIL);
     151             : 
     152       38171 :     if (VSIFReadL(&nLBox, 4, 1, fpVSIL) != 1 ||
     153       18279 :         VSIFReadL(&nTBox, 4, 1, fpVSIL) != 1)
     154             :     {
     155        1614 :         return FALSE;
     156             :     }
     157             : 
     158       18278 :     memcpy(szBoxType, &nTBox, 4);
     159       18278 :     szBoxType[4] = '\0';
     160             : 
     161       18278 :     nLBox = CPL_MSBWORD32(nLBox);
     162             : 
     163       18278 :     if (nLBox != 1)
     164             :     {
     165       18273 :         nBoxLength = nLBox;
     166       18273 :         nDataOffset = nBoxOffset + 8;
     167             :     }
     168             :     else
     169             :     {
     170           5 :         GByte abyXLBox[8] = {0};
     171           5 :         if (VSIFReadL(abyXLBox, 8, 1, fpVSIL) != 1)
     172           0 :             return FALSE;
     173             : 
     174             : #ifdef CPL_HAS_GINT64
     175           5 :         CPL_MSBPTR64(abyXLBox);
     176           5 :         memcpy(&nBoxLength, abyXLBox, 8);
     177             : #else
     178             :         // In case we lack a 64 bit integer type
     179             :         if (abyXLBox[0] != 0 || abyXLBox[1] != 0 || abyXLBox[2] != 0 ||
     180             :             abyXLBox[3] != 0)
     181             :         {
     182             :             CPLError(CE_Failure, CPLE_AppDefined,
     183             :                      "Box size requires a 64 bit integer type");
     184             :             return FALSE;
     185             :         }
     186             :         CPL_MSBPTR32(abyXLBox + 4);
     187             :         memcpy(&nBoxLength, abyXLBox + 4, 4);
     188             : #endif
     189           5 :         if (nBoxLength < 0)
     190             :         {
     191           0 :             CPLDebug("GDALJP2", "Invalid length for box %s", szBoxType);
     192           0 :             return FALSE;
     193             :         }
     194           5 :         nDataOffset = nBoxOffset + 16;
     195             :     }
     196             : 
     197       18278 :     if (nBoxLength == 0 && m_bAllowGetFileSize)
     198             :     {
     199         258 :         if (VSIFSeekL(fpVSIL, 0, SEEK_END) != 0)
     200           0 :             return FALSE;
     201         258 :         nBoxLength = VSIFTellL(fpVSIL) - nBoxOffset;
     202         258 :         if (VSIFSeekL(fpVSIL, nDataOffset, SEEK_SET) != 0)
     203           0 :             return FALSE;
     204             :     }
     205             : 
     206       18278 :     if (EQUAL(szBoxType, "uuid"))
     207             :     {
     208        2763 :         if (VSIFReadL(abyUUID, 16, 1, fpVSIL) != 1)
     209           0 :             return FALSE;
     210        2763 :         nDataOffset += 16;
     211             :     }
     212             : 
     213       18278 :     if (m_bAllowGetFileSize && GetDataLength() < 0)
     214             :     {
     215           0 :         CPLDebug("GDALJP2", "Invalid length for box %s", szBoxType);
     216           0 :         return FALSE;
     217             :     }
     218             : 
     219       18278 :     return TRUE;
     220             : }
     221             : 
     222             : /************************************************************************/
     223             : /*                             IsSuperBox()                             */
     224             : /************************************************************************/
     225             : 
     226        2685 : int GDALJP2Box::IsSuperBox()
     227             : 
     228             : {
     229        4572 :     if (EQUAL(GetType(), "asoc") || EQUAL(GetType(), "jp2h") ||
     230        4572 :         EQUAL(GetType(), "res ") || EQUAL(GetType(), "jumb"))
     231        2364 :         return TRUE;
     232             : 
     233         321 :     return FALSE;
     234             : }
     235             : 
     236             : /************************************************************************/
     237             : /*                            ReadBoxData()                             */
     238             : /************************************************************************/
     239             : 
     240        2792 : GByte *GDALJP2Box::ReadBoxData()
     241             : 
     242             : {
     243        2792 :     GIntBig nDataLength = GetDataLength();
     244        2792 :     if (nDataLength > 100 * 1024 * 1024)
     245             :     {
     246           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     247             :                  "Too big box : " CPL_FRMT_GIB " bytes", nDataLength);
     248           0 :         return nullptr;
     249             :     }
     250             : 
     251        2792 :     if (VSIFSeekL(fpVSIL, nDataOffset, SEEK_SET) != 0)
     252           0 :         return nullptr;
     253             : 
     254             :     char *pszData = static_cast<char *>(
     255        2792 :         VSI_MALLOC_VERBOSE(static_cast<int>(nDataLength) + 1));
     256        2792 :     if (pszData == nullptr)
     257           0 :         return nullptr;
     258             : 
     259        2792 :     if (static_cast<GIntBig>(VSIFReadL(
     260        2792 :             pszData, 1, static_cast<int>(nDataLength), fpVSIL)) != nDataLength)
     261             :     {
     262           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot read box content");
     263           0 :         CPLFree(pszData);
     264           0 :         return nullptr;
     265             :     }
     266             : 
     267        2792 :     pszData[nDataLength] = '\0';
     268             : 
     269        2792 :     return reinterpret_cast<GByte *>(pszData);
     270             : }
     271             : 
     272             : /************************************************************************/
     273             : /*                           GetDataLength()                            */
     274             : /************************************************************************/
     275             : 
     276       39688 : GIntBig GDALJP2Box::GetDataLength() const
     277             : {
     278       39688 :     return nBoxLength - (nDataOffset - nBoxOffset);
     279             : }
     280             : 
     281             : /************************************************************************/
     282             : /*                            DumpReadable()                            */
     283             : /************************************************************************/
     284             : 
     285           0 : int GDALJP2Box::DumpReadable(FILE *fpOut, int nIndentLevel)
     286             : 
     287             : {
     288           0 :     if (fpOut == nullptr)
     289           0 :         fpOut = stdout;
     290             : 
     291           0 :     for (int i = 0; i < nIndentLevel; ++i)
     292           0 :         fprintf(fpOut, "  ");
     293             : 
     294             :     char szBuffer[128];
     295           0 :     CPLsnprintf(szBuffer, sizeof(szBuffer),
     296             :                 "  Type=%s, Offset=" CPL_FRMT_GIB "/" CPL_FRMT_GIB
     297             :                 ", Data Size=" CPL_FRMT_GIB,
     298           0 :                 szBoxType, nBoxOffset, nDataOffset, GetDataLength());
     299           0 :     fprintf(fpOut, "%s", szBuffer);
     300             : 
     301           0 :     if (IsSuperBox())
     302             :     {
     303           0 :         fprintf(fpOut, " (super)");
     304             :     }
     305             : 
     306           0 :     fprintf(fpOut, "\n");
     307             : 
     308           0 :     if (IsSuperBox())
     309             :     {
     310           0 :         GDALJP2Box oSubBox(GetFILE());
     311             : 
     312           0 :         for (oSubBox.ReadFirstChild(this); strlen(oSubBox.GetType()) > 0;
     313           0 :              oSubBox.ReadNextChild(this))
     314             :         {
     315           0 :             oSubBox.DumpReadable(fpOut, nIndentLevel + 1);
     316             :         }
     317             :     }
     318             : 
     319           0 :     if (EQUAL(GetType(), "uuid"))
     320             :     {
     321           0 :         char *pszHex = CPLBinaryToHex(16, GetUUID());
     322           0 :         for (int i = 0; i < nIndentLevel; ++i)
     323           0 :             fprintf(fpOut, "  ");
     324             : 
     325           0 :         fprintf(fpOut, "    UUID=%s", pszHex);
     326             : 
     327           0 :         if (EQUAL(pszHex, "B14BF8BD083D4B43A5AE8CD7D5A6CE03"))
     328           0 :             fprintf(fpOut, " (GeoTIFF)");
     329           0 :         if (EQUAL(pszHex, "96A9F1F1DC98402DA7AED68E34451809"))
     330           0 :             fprintf(fpOut, " (MSI Worldfile)");
     331           0 :         if (EQUAL(pszHex, "BE7ACFCB97A942E89C71999491E3AFAC"))
     332           0 :             fprintf(fpOut, " (XMP)");
     333           0 :         CPLFree(pszHex);
     334             : 
     335           0 :         fprintf(fpOut, "\n");
     336             :     }
     337             : 
     338           0 :     return 0;
     339             : }
     340             : 
     341             : /************************************************************************/
     342             : /*                              SetType()                               */
     343             : /************************************************************************/
     344             : 
     345        1991 : void GDALJP2Box::SetType(const char *pszType)
     346             : 
     347             : {
     348        1991 :     CPLAssert(strlen(pszType) == 4);
     349             : 
     350        1991 :     memcpy(szBoxType, pszType, 4);
     351        1991 :     szBoxType[4] = '\0';
     352        1991 : }
     353             : 
     354             : /************************************************************************/
     355             : /*                          GetWritableBoxData()                        */
     356             : /************************************************************************/
     357             : 
     358          30 : GByte *GDALJP2Box::GetWritableBoxData() const
     359             : {
     360             :     GByte *pabyRet =
     361          30 :         static_cast<GByte *>(CPLMalloc(static_cast<GUInt32>(nBoxLength)));
     362          30 :     const GUInt32 nLBox = CPL_MSBWORD32(static_cast<GUInt32>(nBoxLength));
     363          30 :     memcpy(pabyRet, &nLBox, sizeof(GUInt32));
     364          30 :     memcpy(pabyRet + 4, szBoxType, 4);
     365          30 :     memcpy(pabyRet + 8, pabyData, static_cast<GUInt32>(nBoxLength) - 8);
     366          30 :     return pabyRet;
     367             : }
     368             : 
     369             : /************************************************************************/
     370             : /*                          SetWritableData()                           */
     371             : /************************************************************************/
     372             : 
     373         767 : void GDALJP2Box::SetWritableData(int nLength, const GByte *pabyDataIn)
     374             : 
     375             : {
     376         767 :     CPLFree(pabyData);
     377             : 
     378         767 :     pabyData = static_cast<GByte *>(CPLMalloc(nLength));
     379         767 :     memcpy(pabyData, pabyDataIn, nLength);
     380             : 
     381         767 :     nBoxOffset = -9;  // Virtual offsets for data length computation.
     382         767 :     nDataOffset = -1;
     383             : 
     384         767 :     nBoxLength = 8 + nLength;
     385         767 : }
     386             : 
     387             : /************************************************************************/
     388             : /*                          AppendWritableData()                        */
     389             : /************************************************************************/
     390             : 
     391        4713 : void GDALJP2Box::AppendWritableData(int nLength, const void *pabyDataIn)
     392             : 
     393             : {
     394        4713 :     if (pabyData == nullptr)
     395             :     {
     396        1219 :         nBoxOffset = -9;  // Virtual offsets for data length computation.
     397        1219 :         nDataOffset = -1;
     398        1219 :         nBoxLength = 8;
     399             :     }
     400             : 
     401        4713 :     pabyData = static_cast<GByte *>(
     402        4713 :         CPLRealloc(pabyData, static_cast<size_t>(GetDataLength() + nLength)));
     403        4713 :     memcpy(pabyData + GetDataLength(), pabyDataIn, nLength);
     404             : 
     405        4713 :     nBoxLength += nLength;
     406        4713 : }
     407             : 
     408             : /************************************************************************/
     409             : /*                              AppendUInt32()                          */
     410             : /************************************************************************/
     411             : 
     412         868 : void GDALJP2Box::AppendUInt32(GUInt32 nVal)
     413             : {
     414         868 :     CPL_MSBPTR32(&nVal);
     415         868 :     AppendWritableData(4, &nVal);
     416         868 : }
     417             : 
     418             : /************************************************************************/
     419             : /*                              AppendUInt16()                          */
     420             : /************************************************************************/
     421             : 
     422         614 : void GDALJP2Box::AppendUInt16(GUInt16 nVal)
     423             : {
     424         614 :     CPL_MSBPTR16(&nVal);
     425         614 :     AppendWritableData(2, &nVal);
     426         614 : }
     427             : 
     428             : /************************************************************************/
     429             : /*                              AppendUInt8()                           */
     430             : /************************************************************************/
     431             : 
     432        1996 : void GDALJP2Box::AppendUInt8(GByte nVal)
     433             : {
     434        1996 :     AppendWritableData(1, &nVal);
     435        1996 : }
     436             : 
     437             : /************************************************************************/
     438             : /*                           CreateUUIDBox()                            */
     439             : /************************************************************************/
     440             : 
     441         226 : GDALJP2Box *GDALJP2Box::CreateUUIDBox(const GByte *pabyUUID, int nDataSize,
     442             :                                       const GByte *pabyDataIn)
     443             : 
     444             : {
     445         226 :     GDALJP2Box *const poBox = new GDALJP2Box();
     446         226 :     poBox->SetType("uuid");
     447             : 
     448         226 :     poBox->AppendWritableData(16, pabyUUID);
     449         226 :     poBox->AppendWritableData(nDataSize, pabyDataIn);
     450             : 
     451         226 :     return poBox;
     452             : }
     453             : 
     454             : /************************************************************************/
     455             : /*                           CreateAsocBox()                            */
     456             : /************************************************************************/
     457             : 
     458         198 : GDALJP2Box *GDALJP2Box::CreateAsocBox(int nCount,
     459             :                                       const GDALJP2Box *const *papoBoxes)
     460             : {
     461         198 :     return CreateSuperBox("asoc", nCount, papoBoxes);
     462             : }
     463             : 
     464             : /************************************************************************/
     465             : /*                           CreateAsocBox()                            */
     466             : /************************************************************************/
     467             : 
     468         453 : GDALJP2Box *GDALJP2Box::CreateSuperBox(const char *pszType, int nCount,
     469             :                                        const GDALJP2Box *const *papoBoxes)
     470             : {
     471         453 :     int nDataSize = 0;
     472             : 
     473             :     /* -------------------------------------------------------------------- */
     474             :     /*      Compute size of data area of asoc box.                          */
     475             :     /* -------------------------------------------------------------------- */
     476        1406 :     for (int iBox = 0; iBox < nCount; ++iBox)
     477         953 :         nDataSize += 8 + static_cast<int>(papoBoxes[iBox]->GetDataLength());
     478             : 
     479         453 :     GByte *pabyNext = static_cast<GByte *>(CPLMalloc(nDataSize));
     480         453 :     GByte *pabyCompositeData = pabyNext;
     481             : 
     482             :     /* -------------------------------------------------------------------- */
     483             :     /*      Copy subboxes headers and data into buffer.                     */
     484             :     /* -------------------------------------------------------------------- */
     485        1406 :     for (int iBox = 0; iBox < nCount; ++iBox)
     486             :     {
     487         953 :         GUInt32 nLBox =
     488         953 :             CPL_MSBWORD32(static_cast<GUInt32>(papoBoxes[iBox]->nBoxLength));
     489         953 :         memcpy(pabyNext, &nLBox, 4);
     490         953 :         pabyNext += 4;
     491             : 
     492         953 :         memcpy(pabyNext, papoBoxes[iBox]->szBoxType, 4);
     493         953 :         pabyNext += 4;
     494             : 
     495         953 :         memcpy(pabyNext, papoBoxes[iBox]->pabyData,
     496         953 :                static_cast<int>(papoBoxes[iBox]->GetDataLength()));
     497         953 :         pabyNext += papoBoxes[iBox]->GetDataLength();
     498             :     }
     499             : 
     500             :     /* -------------------------------------------------------------------- */
     501             :     /*      Create asoc box.                                                */
     502             :     /* -------------------------------------------------------------------- */
     503         453 :     GDALJP2Box *const poAsoc = new GDALJP2Box();
     504             : 
     505         453 :     poAsoc->SetType(pszType);
     506         453 :     poAsoc->SetWritableData(nDataSize, pabyCompositeData);
     507             : 
     508         453 :     CPLFree(pabyCompositeData);
     509             : 
     510         453 :     return poAsoc;
     511             : }
     512             : 
     513             : /************************************************************************/
     514             : /*                            CreateLblBox()                            */
     515             : /************************************************************************/
     516             : 
     517          86 : GDALJP2Box *GDALJP2Box::CreateLblBox(const char *pszLabel)
     518             : 
     519             : {
     520          86 :     GDALJP2Box *const poBox = new GDALJP2Box();
     521          86 :     poBox->SetType("lbl ");
     522          86 :     poBox->SetWritableData(static_cast<int>(strlen(pszLabel) + 1),
     523             :                            reinterpret_cast<const GByte *>(pszLabel));
     524             : 
     525          86 :     return poBox;
     526             : }
     527             : 
     528             : /************************************************************************/
     529             : /*                       CreateLabelledXMLAssoc()                       */
     530             : /************************************************************************/
     531             : 
     532         107 : GDALJP2Box *GDALJP2Box::CreateLabelledXMLAssoc(const char *pszLabel,
     533             :                                                const char *pszXML)
     534             : 
     535             : {
     536         214 :     GDALJP2Box oLabel;
     537         107 :     oLabel.SetType("lbl ");
     538         107 :     oLabel.SetWritableData(static_cast<int>(strlen(pszLabel) + 1),
     539             :                            reinterpret_cast<const GByte *>(pszLabel));
     540             : 
     541         214 :     GDALJP2Box oXML;
     542         107 :     oXML.SetType("xml ");
     543         107 :     oXML.SetWritableData(static_cast<int>(strlen(pszXML) + 1),
     544             :                          reinterpret_cast<const GByte *>(pszXML));
     545             : 
     546         107 :     GDALJP2Box *aoList[2] = {&oLabel, &oXML};
     547             : 
     548         214 :     return CreateAsocBox(2, aoList);
     549             : }
     550             : 
     551             : /************************************************************************/
     552             : /*                    CreateJUMBFDescriptionBox()                       */
     553             : /************************************************************************/
     554             : 
     555          38 : GDALJP2Box *GDALJP2Box::CreateJUMBFDescriptionBox(const GByte *pabyUUIDType,
     556             :                                                   const char *pszLabel)
     557             : 
     558             : {
     559          38 :     GDALJP2Box *const poBox = new GDALJP2Box();
     560          38 :     poBox->SetType("jumd");
     561             : 
     562          38 :     poBox->AppendWritableData(16, pabyUUIDType);
     563          38 :     poBox->AppendUInt8(3);  // requestable field
     564          38 :     const size_t nLabelLen = strlen(pszLabel) + 1;
     565          38 :     poBox->AppendWritableData(static_cast<int>(nLabelLen), pszLabel);
     566             : 
     567          38 :     return poBox;
     568             : }
     569             : 
     570             : /************************************************************************/
     571             : /*                         CreateJUMBFBox()                             */
     572             : /************************************************************************/
     573             : 
     574          38 : GDALJP2Box *GDALJP2Box::CreateJUMBFBox(const GDALJP2Box *poJUMBFDescriptionBox,
     575             :                                        int nCount,
     576             :                                        const GDALJP2Box *const *papoBoxes)
     577             : {
     578          76 :     std::vector<const GDALJP2Box *> apoBoxes;
     579          38 :     apoBoxes.push_back(poJUMBFDescriptionBox);
     580          38 :     apoBoxes.insert(apoBoxes.end(), papoBoxes, papoBoxes + nCount);
     581          38 :     return CreateSuperBox("jumb", static_cast<int>(apoBoxes.size()),
     582         114 :                           apoBoxes.data());
     583             : }
     584             : 
     585             : /*! @endcond */

Generated by: LCOV version 1.14