LCOV - code coverage report
Current view: top level - frmts/envisat - EnvisatFile.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 497 0.0 %
Date: 2024-11-21 22:18:42 Functions: 0 28 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  APP ENVISAT Support
       5             :  * Purpose:  Low Level Envisat file access (read/write) API.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2001, Atlantis Scientific, Inc.
      10             :  * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_string.h"
      16             : 
      17             : #ifndef APP_BUILD
      18             : #define GDAL_BUILD
      19             : #include "cpl_conv.h"
      20             : #include "EnvisatFile.h"
      21             : 
      22             : #else
      23             : #include "APP/app.h"
      24             : #include "util/Files/EnvisatFile.h"
      25             : #endif
      26             : 
      27           0 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      28             : {
      29           0 : }
      30             : 
      31           0 : CPL_INLINE static void CPL_IGNORE_RET_VAL_SIZET(CPL_UNUSED size_t unused)
      32             : {
      33           0 : }
      34             : 
      35             : typedef struct
      36             : {
      37             :     char *ds_name;
      38             :     char *ds_type;
      39             :     char *filename;
      40             :     int ds_offset;
      41             :     int ds_size;
      42             :     int num_dsr;
      43             :     int dsr_size;
      44             : } EnvisatDatasetInfo;
      45             : 
      46             : typedef struct
      47             : {
      48             :     char *key;
      49             :     char *value;
      50             :     size_t value_len;
      51             :     char *units;
      52             :     char *literal_line;
      53             :     int value_offset;
      54             : } EnvisatNameValue;
      55             : 
      56             : struct EnvisatFile_tag
      57             : {
      58             :     VSILFILE *fp;
      59             :     char *filename;
      60             :     int updatable;
      61             :     int header_dirty;
      62             :     int dsd_offset;
      63             : 
      64             :     int mph_count;
      65             :     EnvisatNameValue **mph_entries;
      66             : 
      67             :     int sph_count;
      68             :     EnvisatNameValue **sph_entries;
      69             : 
      70             :     int ds_count;
      71             :     EnvisatDatasetInfo **ds_info;
      72             : };
      73             : 
      74             : #ifdef GDAL_BUILD
      75             : #define SUCCESS 0
      76             : #define FAILURE 1
      77             : #define SendError(text) CPLError(CE_Failure, CPLE_AppDefined, "%s", text)
      78             : #endif
      79             : 
      80             : #define MPH_SIZE 1247
      81             : 
      82             : /*
      83             :  * API For handling name/value lists.
      84             :  */
      85             : int S_NameValueList_Parse(const char *text, int text_offset, int *entry_count,
      86             :                           EnvisatNameValue ***entries);
      87             : void S_NameValueList_Destroy(int *entry_count, EnvisatNameValue ***entries);
      88             : int S_NameValueList_FindKey(const char *key, int entry_count,
      89             :                             EnvisatNameValue **entries);
      90             : const char *S_NameValueList_FindValue(const char *key, int entry_count,
      91             :                                       EnvisatNameValue **entries,
      92             :                                       const char *default_value);
      93             : 
      94             : int S_NameValueList_Rewrite(VSILFILE *fp, int entry_count,
      95             :                             EnvisatNameValue **entries);
      96             : 
      97             : EnvisatNameValue *S_EnivsatFile_FindNameValue(EnvisatFile *self,
      98             :                                               EnvisatFile_HeaderFlag mph_or_sph,
      99             :                                               const char *key);
     100             : 
     101             : /*-----------------------------------------------------------------------------
     102             : 
     103             : Name:
     104             :     Envisat_SetupLevel0
     105             : 
     106             : Purpose:
     107             :     Patch up missing information about SPH, and datasets for incomplete
     108             :     level 0 signal datasets.
     109             : 
     110             : Description:
     111             : 
     112             : Inputs:
     113             :     self -- Envisat file handle.
     114             : 
     115             : Outputs:
     116             : 
     117             : Returns:
     118             :     SUCCESS or FAILURE
     119             : 
     120             : -----------------------------------------------------------------------------*/
     121             : 
     122           0 : static int EnvisatFile_SetupLevel0(EnvisatFile *self)
     123             : 
     124             : {
     125             :     int file_length;
     126             :     unsigned char header[68];
     127             :     EnvisatDatasetInfo *ds_info;
     128             : 
     129           0 :     self->dsd_offset = 0;
     130           0 :     self->ds_count = 1;
     131           0 :     self->ds_info = (EnvisatDatasetInfo **)CPLCalloc(
     132           0 :         sizeof(EnvisatDatasetInfo *), self->ds_count);
     133             : 
     134           0 :     if (self->ds_info == NULL)
     135           0 :         return FAILURE;
     136             : 
     137             :     /*
     138             :      * Figure out how long the file is.
     139             :      */
     140             : 
     141           0 :     CPL_IGNORE_RET_VAL_INT(VSIFSeekL(self->fp, 0, SEEK_END));
     142           0 :     file_length = (int)VSIFTellL(self->fp);
     143             : 
     144             :     /*
     145             :      * Read the first record header, and verify the well known values.
     146             :      */
     147           0 :     CPL_IGNORE_RET_VAL_INT(VSIFSeekL(self->fp, 3203, SEEK_SET));
     148           0 :     CPL_IGNORE_RET_VAL_SIZET(VSIFReadL(header, 68, 1, self->fp));
     149             : 
     150           0 :     if (header[38] != 0 || header[39] != 0x1d || header[40] != 0 ||
     151           0 :         header[41] != 0x54)
     152             :     {
     153           0 :         SendError("Didn't get expected Data Field Header Length, or Mode ID\n"
     154             :                   "values for the first data record.");
     155           0 :         return FAILURE;
     156             :     }
     157             : 
     158             :     /*
     159             :      * Then build the dataset into structure from that.
     160             :      */
     161           0 :     ds_info = (EnvisatDatasetInfo *)CPLCalloc(sizeof(EnvisatDatasetInfo), 1);
     162             : 
     163           0 :     ds_info->ds_name = CPLStrdup("ASAR SOURCE PACKETS         ");
     164           0 :     ds_info->ds_type = CPLStrdup("M");
     165           0 :     ds_info->filename = CPLStrdup(
     166             :         "                                                              ");
     167           0 :     ds_info->ds_offset = 3203;
     168           0 :     ds_info->dsr_size = -1;
     169           0 :     ds_info->num_dsr = 0;
     170           0 :     ds_info->ds_size = file_length - ds_info->ds_offset;
     171             : 
     172           0 :     self->ds_info[0] = ds_info;
     173             : 
     174           0 :     return SUCCESS;
     175             : }
     176             : 
     177             : /*-----------------------------------------------------------------------------
     178             : 
     179             : Name:
     180             :     Envisat_Open
     181             : 
     182             : Purpose:
     183             :     Open an ENVISAT formatted file, and read all headers.
     184             : 
     185             : Description:
     186             : 
     187             : Inputs:
     188             :     filename -- name of Envisat file.
     189             :     mode -- either "r" for read access, or "r+" for read/write access.
     190             : 
     191             : Outputs:
     192             :     self -- file handle, NULL on FAILURE.
     193             : 
     194             : Returns:
     195             :     SUCCESS or FAILURE
     196             : 
     197             : -----------------------------------------------------------------------------*/
     198             : 
     199           0 : int EnvisatFile_Open(EnvisatFile **self_ptr, const char *filename,
     200             :                      const char *mode)
     201             : 
     202             : {
     203             :     VSILFILE *fp;
     204             :     EnvisatFile *self;
     205             :     char mph_data[1248];
     206             :     char *sph_data, *ds_data;
     207             :     int sph_size, num_dsd, dsd_size, i;
     208             : 
     209           0 :     *self_ptr = NULL;
     210             : 
     211             :     /*
     212             :      * Check for legal mode argument.  Force to be binary for correct
     213             :      * operation on DOS file systems.
     214             :      */
     215           0 :     if (strcmp(mode, "r") == 0)
     216           0 :         mode = "rb";
     217           0 :     else if (strcmp(mode, "r+") == 0)
     218           0 :         mode = "rb+";
     219             :     else
     220             :     {
     221           0 :         SendError("Illegal mode value used in EnvisatFile_Open(), only "
     222             :                   "\"r\" and \"r+\" are supported.");
     223           0 :         return FAILURE;
     224             :     }
     225             : 
     226             :     /*
     227             :      * Try to open the file, and report failure.
     228             :      */
     229             : 
     230           0 :     fp = VSIFOpenL(filename, mode);
     231             : 
     232           0 :     if (fp == NULL)
     233             :     {
     234             :         char error_buf[2048];
     235             : 
     236           0 :         snprintf(error_buf, sizeof(error_buf),
     237             :                  "Unable to open file \"%s\" in EnvisatFile_Open().", filename);
     238             : 
     239           0 :         SendError(error_buf);
     240           0 :         return FAILURE;
     241             :     }
     242             : 
     243             :     /*
     244             :      * Create, and initialize the EnvisatFile structure.
     245             :      */
     246           0 :     self = (EnvisatFile *)CPLCalloc(sizeof(EnvisatFile), 1);
     247           0 :     if (self == NULL)
     248           0 :         return FAILURE;
     249             : 
     250           0 :     self->fp = fp;
     251           0 :     self->filename = CPLStrdup(filename);
     252           0 :     self->header_dirty = 0;
     253           0 :     self->updatable = (strcmp(mode, "rb+") == 0);
     254             : 
     255             :     /*
     256             :      * Read the MPH, and process it as a group of name/value pairs.
     257             :      */
     258             : 
     259           0 :     if (VSIFReadL(mph_data, 1, MPH_SIZE, fp) != MPH_SIZE)
     260             :     {
     261           0 :         EnvisatFile_Close(self);
     262           0 :         SendError("VSIFReadL() for mph failed.");
     263           0 :         return FAILURE;
     264             :     }
     265             : 
     266           0 :     mph_data[MPH_SIZE] = '\0';
     267           0 :     if (S_NameValueList_Parse(mph_data, 0, &(self->mph_count),
     268             :                               &(self->mph_entries)) == FAILURE)
     269             :     {
     270           0 :         EnvisatFile_Close(self);
     271           0 :         return FAILURE;
     272             :     }
     273             : 
     274             :     /*
     275             :      * Is this an incomplete level 0 file?
     276             :      */
     277           0 :     if (EnvisatFile_GetKeyValueAsInt(self, MPH, "SPH_SIZE", -1) == 0 &&
     278           0 :         STARTS_WITH(EnvisatFile_GetKeyValueAsString(self, MPH, "PRODUCT", ""),
     279             :                     "ASA_IM__0P"))
     280             :     {
     281             : 
     282           0 :         if (EnvisatFile_SetupLevel0(self) == FAILURE)
     283             :         {
     284           0 :             EnvisatFile_Close(self);
     285           0 :             return FAILURE;
     286             :         }
     287             :         else
     288             :         {
     289           0 :             *self_ptr = self;
     290           0 :             return SUCCESS;
     291             :         }
     292             :     }
     293             : 
     294             :     /*
     295             :      * Read the SPH, and process it as a group of name/value pairs.
     296             :      */
     297           0 :     sph_size = EnvisatFile_GetKeyValueAsInt(self, MPH, "SPH_SIZE", 0);
     298             : 
     299           0 :     if (sph_size == 0)
     300             :     {
     301           0 :         SendError("File does not appear to have SPH,"
     302             :                   " SPH_SIZE not set, or zero.");
     303           0 :         EnvisatFile_Close(self);
     304           0 :         return FAILURE;
     305             :     }
     306             : 
     307           0 :     sph_data = (char *)CPLMalloc(sph_size + 1);
     308           0 :     if (sph_data == NULL)
     309             :     {
     310           0 :         EnvisatFile_Close(self);
     311           0 :         return FAILURE;
     312             :     }
     313             : 
     314           0 :     if ((int)VSIFReadL(sph_data, 1, sph_size, fp) != sph_size)
     315             :     {
     316           0 :         CPLFree(sph_data);
     317           0 :         EnvisatFile_Close(self);
     318           0 :         SendError("VSIFReadL() for sph failed.");
     319           0 :         return FAILURE;
     320             :     }
     321             : 
     322           0 :     sph_data[sph_size] = '\0';
     323           0 :     ds_data = strstr(sph_data, "DS_NAME");
     324           0 :     if (ds_data != NULL)
     325             :     {
     326           0 :         self->dsd_offset = (int)(ds_data - sph_data) + MPH_SIZE;
     327           0 :         *(ds_data - 1) = '\0';
     328             :     }
     329             : 
     330           0 :     if (S_NameValueList_Parse(sph_data, MPH_SIZE, &(self->sph_count),
     331             :                               &(self->sph_entries)) == FAILURE)
     332             :     {
     333           0 :         CPLFree(sph_data);
     334           0 :         EnvisatFile_Close(self);
     335           0 :         return FAILURE;
     336             :     }
     337             : 
     338             :     /*
     339             :      * Parse the Dataset Definitions.
     340             :      */
     341           0 :     num_dsd = EnvisatFile_GetKeyValueAsInt(self, MPH, "NUM_DSD", 0);
     342           0 :     dsd_size = EnvisatFile_GetKeyValueAsInt(self, MPH, "DSD_SIZE", 0);
     343             : 
     344           0 :     if (num_dsd > 0 && ds_data == NULL)
     345             :     {
     346           0 :         CPLFree(sph_data);
     347           0 :         SendError("DSDs indicated in MPH, but not found in SPH.");
     348           0 :         EnvisatFile_Close(self);
     349           0 :         return FAILURE;
     350             :     }
     351             : 
     352           0 :     self->ds_info =
     353           0 :         (EnvisatDatasetInfo **)CPLCalloc(sizeof(EnvisatDatasetInfo *), num_dsd);
     354           0 :     if (self->ds_info == NULL)
     355             :     {
     356           0 :         CPLFree(sph_data);
     357           0 :         EnvisatFile_Close(self);
     358           0 :         return FAILURE;
     359             :     }
     360             : 
     361           0 :     for (i = 0; i < num_dsd; i++)
     362             :     {
     363           0 :         int dsdh_count = 0;
     364           0 :         EnvisatNameValue **dsdh_entries = NULL;
     365             :         char *dsd_data;
     366             :         EnvisatDatasetInfo *ds_info;
     367             : 
     368             :         /*
     369             :          * We parse each DSD grouping into a name/value list.
     370             :          */
     371           0 :         dsd_data = ds_data + i * dsd_size;
     372           0 :         dsd_data[dsd_size - 1] = '\0';
     373             : 
     374           0 :         if (S_NameValueList_Parse(dsd_data, 0, &dsdh_count, &dsdh_entries) ==
     375             :             FAILURE)
     376             :         {
     377           0 :             CPLFree(sph_data);
     378           0 :             EnvisatFile_Close(self);
     379           0 :             return FAILURE;
     380             :         }
     381             : 
     382             :         /*
     383             :          * Then build the dataset into structure from that.
     384             :          */
     385             :         ds_info =
     386           0 :             (EnvisatDatasetInfo *)CPLCalloc(sizeof(EnvisatDatasetInfo), 1);
     387             : 
     388           0 :         ds_info->ds_name = CPLStrdup(
     389             :             S_NameValueList_FindValue("DS_NAME", dsdh_count, dsdh_entries, ""));
     390           0 :         ds_info->ds_type = CPLStrdup(
     391             :             S_NameValueList_FindValue("DS_TYPE", dsdh_count, dsdh_entries, ""));
     392           0 :         ds_info->filename = CPLStrdup(S_NameValueList_FindValue(
     393             :             "FILENAME", dsdh_count, dsdh_entries, ""));
     394           0 :         ds_info->ds_offset = atoi(S_NameValueList_FindValue(
     395             :             "DS_OFFSET", dsdh_count, dsdh_entries, "0"));
     396           0 :         ds_info->ds_size = atoi(S_NameValueList_FindValue("DS_SIZE", dsdh_count,
     397             :                                                           dsdh_entries, "0"));
     398           0 :         ds_info->num_dsr = atoi(S_NameValueList_FindValue("NUM_DSR", dsdh_count,
     399             :                                                           dsdh_entries, "0"));
     400           0 :         ds_info->dsr_size = atoi(S_NameValueList_FindValue(
     401             :             "DSR_SIZE", dsdh_count, dsdh_entries, "0"));
     402             : 
     403           0 :         S_NameValueList_Destroy(&dsdh_count, &dsdh_entries);
     404             : 
     405           0 :         self->ds_info[i] = ds_info;
     406           0 :         self->ds_count++;
     407             :     }
     408             : 
     409           0 :     CPLFree(sph_data);
     410             : 
     411             :     /*
     412             :      * Return successfully.
     413             :      */
     414           0 :     *self_ptr = self;
     415             : 
     416           0 :     return SUCCESS;
     417             : }
     418             : 
     419             : /*-----------------------------------------------------------------------------
     420             : 
     421             : Name:
     422             :     EnvisatFile_Create
     423             : 
     424             : Purpose:
     425             :     Create a new ENVISAT formatted file based on a template file.
     426             : 
     427             : Description:
     428             : 
     429             : Inputs:
     430             :     filename -- name of Envisat file.
     431             :     template_file -- name of envisat file header to utilize as template.
     432             : 
     433             : Outputs:
     434             :     self -- file handle, NULL on FAILURE.
     435             : 
     436             : Returns:
     437             :     SUCCESS or FAILURE
     438             : 
     439             : -----------------------------------------------------------------------------*/
     440             : 
     441           0 : int EnvisatFile_Create(EnvisatFile **self_ptr, const char *filename,
     442             :                        const char *template_file)
     443             : 
     444             : {
     445             :     int template_size;
     446             :     char *template_data;
     447             :     VSILFILE *fp;
     448             : 
     449             :     /*
     450             :      * Try to open the template file, and read it into memory.
     451             :      */
     452             : 
     453           0 :     fp = VSIFOpenL(template_file, "rb");
     454             : 
     455           0 :     if (fp == NULL)
     456             :     {
     457             :         char error_buf[2048];
     458             : 
     459           0 :         snprintf(error_buf, sizeof(error_buf),
     460             :                  "Unable to open file \"%s\" in EnvisatFile_Create().",
     461             :                  template_file);
     462             : 
     463           0 :         SendError(error_buf);
     464           0 :         return FAILURE;
     465             :     }
     466             : 
     467           0 :     CPL_IGNORE_RET_VAL_INT(VSIFSeekL(fp, 0, SEEK_END));
     468           0 :     template_size = (int)VSIFTellL(fp);
     469             : 
     470           0 :     template_data = (char *)CPLMalloc(template_size);
     471             : 
     472           0 :     CPL_IGNORE_RET_VAL_INT(VSIFSeekL(fp, 0, SEEK_SET));
     473           0 :     CPL_IGNORE_RET_VAL_SIZET(VSIFReadL(template_data, template_size, 1, fp));
     474           0 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     475             : 
     476             :     /*
     477             :      * Try to write the template out to the new filename.
     478             :      */
     479             : 
     480           0 :     fp = VSIFOpenL(filename, "wb");
     481           0 :     if (fp == NULL)
     482             :     {
     483             :         char error_buf[2048];
     484             : 
     485           0 :         snprintf(error_buf, sizeof(error_buf),
     486             :                  "Unable to open file \"%s\" in EnvisatFile_Create().",
     487             :                  filename);
     488             : 
     489           0 :         SendError(error_buf);
     490           0 :         return FAILURE;
     491             :     }
     492             : 
     493           0 :     CPL_IGNORE_RET_VAL_SIZET(VSIFWriteL(template_data, template_size, 1, fp));
     494           0 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     495             : 
     496           0 :     CPLFree(template_data);
     497             : 
     498             :     /*
     499             :      * Now just open the file normally.
     500             :      */
     501             : 
     502           0 :     return EnvisatFile_Open(self_ptr, filename, "r+");
     503             : }
     504             : 
     505             : /*-----------------------------------------------------------------------------
     506             : 
     507             : Name:
     508             :     EnvisatFile_GetCurrentLength
     509             : 
     510             : Purpose:
     511             :     Fetch the current file length.
     512             : 
     513             : Description:
     514             :     The length is computed by scanning the dataset definitions, not the
     515             :     physical file length.
     516             : 
     517             : Inputs:
     518             :     self -- the file to operate on.
     519             : 
     520             : Outputs:
     521             : 
     522             : Returns:
     523             :     Returns length or -1 on failure.
     524             : 
     525             : -----------------------------------------------------------------------------*/
     526             : 
     527           0 : int EnvisatFile_GetCurrentLength(EnvisatFile *self)
     528             : 
     529             : {
     530             :     int length;
     531             :     int ds;
     532             :     int ds_offset;
     533             :     int ds_size;
     534             : 
     535           0 :     length = MPH_SIZE + EnvisatFile_GetKeyValueAsInt(self, MPH, "SPH_SIZE", 0);
     536             : 
     537           0 :     for (ds = 0;
     538           0 :          EnvisatFile_GetDatasetInfo(self, ds, NULL, NULL, NULL, &ds_offset,
     539             :                                     &ds_size, NULL, NULL) != FAILURE;
     540           0 :          ds++)
     541             :     {
     542           0 :         if (ds_offset != 0 && (ds_offset + ds_size) > length)
     543           0 :             length = ds_offset + ds_size;
     544             :     }
     545             : 
     546           0 :     return length;
     547             : }
     548             : 
     549             : /*-----------------------------------------------------------------------------
     550             : 
     551             : Name:
     552             :     EnvisatFile_RewriteHeader
     553             : 
     554             : Purpose:
     555             :     Update the envisat file header on disk to match the in-memory image.
     556             : 
     557             : Description:
     558             : 
     559             : Inputs:
     560             :     self -- handle for file to close.
     561             : 
     562             : Outputs:
     563             : 
     564             : Returns:
     565             :     SUCCESS or FAILURE.
     566             : 
     567             : -----------------------------------------------------------------------------*/
     568             : 
     569           0 : static int EnvisatFile_RewriteHeader(EnvisatFile *self)
     570             : 
     571             : {
     572             :     int dsd, dsd_size;
     573             : 
     574             :     /*
     575             :      * Rewrite MPH and SPH headers.
     576             :      */
     577           0 :     if (S_NameValueList_Rewrite(self->fp, self->mph_count, self->mph_entries) ==
     578             :         FAILURE)
     579           0 :         return FAILURE;
     580             : 
     581           0 :     if (S_NameValueList_Rewrite(self->fp, self->sph_count, self->sph_entries) ==
     582             :         FAILURE)
     583           0 :         return FAILURE;
     584             : 
     585             :     /*
     586             :      * Rewrite DSDs.  We actually have to read each, and reparse to set
     587             :      * the individual parameters properly.
     588             :      */
     589           0 :     dsd_size = EnvisatFile_GetKeyValueAsInt(self, MPH, "DSD_SIZE", 0);
     590           0 :     if (dsd_size == 0)
     591           0 :         return FAILURE;
     592             : 
     593           0 :     for (dsd = 0; dsd < self->ds_count; dsd++)
     594             :     {
     595             :         char *dsd_text;
     596           0 :         int dsdh_count = 0, key_index;
     597           0 :         EnvisatNameValue **dsdh_entries = NULL;
     598             : 
     599           0 :         dsd_text = (char *)CPLCalloc(1, dsd_size + 1);
     600           0 :         if (VSIFSeekL(self->fp, self->dsd_offset + dsd * dsd_size, SEEK_SET) !=
     601             :             0)
     602             :         {
     603           0 :             SendError("VSIFSeekL() failed in EnvisatFile_RewriteHeader()");
     604           0 :             CPLFree(dsd_text);
     605           0 :             return FAILURE;
     606             :         }
     607             : 
     608           0 :         if ((int)VSIFReadL(dsd_text, 1, dsd_size, self->fp) != dsd_size)
     609             :         {
     610           0 :             SendError("VSIFReadL() failed in EnvisatFile_RewriteHeader()");
     611           0 :             return FAILURE;
     612             :         }
     613             : 
     614           0 :         if (S_NameValueList_Parse(dsd_text, self->dsd_offset + dsd * dsd_size,
     615             :                                   &dsdh_count, &dsdh_entries) == FAILURE)
     616           0 :             return FAILURE;
     617             : 
     618           0 :         CPLFree(dsd_text);
     619             : 
     620             :         key_index =
     621           0 :             S_NameValueList_FindKey("DS_OFFSET", dsdh_count, dsdh_entries);
     622           0 :         if (key_index == -1)
     623           0 :             continue;
     624             : 
     625           0 :         snprintf(dsdh_entries[key_index]->value,
     626           0 :                  dsdh_entries[key_index]->value_len, "%+021d",
     627           0 :                  self->ds_info[dsd]->ds_offset);
     628             : 
     629             :         key_index =
     630           0 :             S_NameValueList_FindKey("DS_SIZE", dsdh_count, dsdh_entries);
     631           0 :         snprintf(dsdh_entries[key_index]->value,
     632           0 :                  dsdh_entries[key_index]->value_len, "%+021d",
     633           0 :                  self->ds_info[dsd]->ds_size);
     634             : 
     635             :         key_index =
     636           0 :             S_NameValueList_FindKey("NUM_DSR", dsdh_count, dsdh_entries);
     637           0 :         snprintf(dsdh_entries[key_index]->value,
     638           0 :                  dsdh_entries[key_index]->value_len, "%+011d",
     639           0 :                  self->ds_info[dsd]->num_dsr);
     640             : 
     641             :         key_index =
     642           0 :             S_NameValueList_FindKey("DSR_SIZE", dsdh_count, dsdh_entries);
     643           0 :         snprintf(dsdh_entries[key_index]->value,
     644           0 :                  dsdh_entries[key_index]->value_len, "%+011d",
     645           0 :                  self->ds_info[dsd]->dsr_size);
     646             : 
     647           0 :         if (S_NameValueList_Rewrite(self->fp, dsdh_count, dsdh_entries) ==
     648             :             FAILURE)
     649           0 :             return FAILURE;
     650             : 
     651           0 :         S_NameValueList_Destroy(&dsdh_count, &dsdh_entries);
     652             :     }
     653             : 
     654           0 :     self->header_dirty = 0;
     655             : 
     656           0 :     return SUCCESS;
     657             : }
     658             : 
     659             : /*-----------------------------------------------------------------------------
     660             : 
     661             : Name:
     662             :     EnvisatFile_Close
     663             : 
     664             : Purpose:
     665             :     Close an ENVISAT formatted file, releasing all associated resources.
     666             : 
     667             : Description:
     668             : 
     669             : Inputs:
     670             :     self -- handle for file to close.
     671             : 
     672             : Outputs:
     673             : 
     674             : Returns:
     675             : 
     676             : 
     677             : -----------------------------------------------------------------------------*/
     678             : 
     679           0 : void EnvisatFile_Close(EnvisatFile *self)
     680             : 
     681             : {
     682             :     int i;
     683             : 
     684             :     /*
     685             :      * Do we need to write out the header information?
     686             :      */
     687           0 :     if (self->header_dirty)
     688           0 :         EnvisatFile_RewriteHeader(self);
     689             : 
     690             :     /*
     691             :      * Close file.
     692             :      */
     693           0 :     if (self->fp != NULL)
     694           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(self->fp));
     695             : 
     696             :     /*
     697             :      * Clean up data structures.
     698             :      */
     699           0 :     S_NameValueList_Destroy(&(self->mph_count), &(self->mph_entries));
     700           0 :     S_NameValueList_Destroy(&(self->sph_count), &(self->sph_entries));
     701             : 
     702           0 :     for (i = 0; i < self->ds_count; i++)
     703             :     {
     704           0 :         if (self->ds_info != NULL && self->ds_info[i] != NULL)
     705             :         {
     706           0 :             CPLFree(self->ds_info[i]->ds_name);
     707           0 :             CPLFree(self->ds_info[i]->ds_type);
     708           0 :             CPLFree(self->ds_info[i]->filename);
     709           0 :             CPLFree(self->ds_info[i]);
     710             :         }
     711             :     }
     712           0 :     if (self->ds_info != NULL)
     713           0 :         CPLFree(self->ds_info);
     714           0 :     if (self->filename != NULL)
     715           0 :         CPLFree(self->filename);
     716             : 
     717           0 :     CPLFree(self);
     718           0 : }
     719             : 
     720             : /*-----------------------------------------------------------------------------
     721             : 
     722             : Name:
     723             :     EnvisatFile_GetFilename
     724             : 
     725             : Purpose:
     726             :     Fetch name of this Envisat file.
     727             : 
     728             : Description:
     729             : 
     730             : Inputs:
     731             :     self -- handle for file to get name of.
     732             : 
     733             : Outputs:
     734             : 
     735             : Returns:
     736             :     const pointer to internal copy of the filename.  Do not alter or free.
     737             : 
     738             : 
     739             : -----------------------------------------------------------------------------*/
     740             : 
     741           0 : const char *EnvisatFile_GetFilename(EnvisatFile *self)
     742             : 
     743             : {
     744           0 :     return self->filename;
     745             : }
     746             : 
     747             : /*-----------------------------------------------------------------------------
     748             : 
     749             : Name:
     750             :     EnvisatFile_GetKeyByIndex()
     751             : 
     752             : Purpose:
     753             :     Fetch the key with the indicated index.
     754             : 
     755             : Description:
     756             :     This function can be used to "discover" the set of available keys by
     757             :     by scanning with index values starting at zero and ending when a NULL
     758             :     is returned.
     759             : 
     760             : Inputs:
     761             :     self -- the file to be searched.
     762             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
     763             :     key_index -- key index, from zero to number of keys-1.
     764             : 
     765             : Outputs:
     766             : 
     767             : Returns:
     768             :     pointer to key name or NULL on failure.
     769             : 
     770             : -----------------------------------------------------------------------------*/
     771             : 
     772           0 : const char *EnvisatFile_GetKeyByIndex(EnvisatFile *self,
     773             :                                       EnvisatFile_HeaderFlag mph_or_sph,
     774             :                                       int key_index)
     775             : 
     776             : {
     777             :     int entry_count;
     778             :     EnvisatNameValue **entries;
     779             : 
     780             :     /*
     781             :      * Select source list.
     782             :      */
     783           0 :     if (mph_or_sph == MPH)
     784             :     {
     785           0 :         entry_count = self->mph_count;
     786           0 :         entries = self->mph_entries;
     787             :     }
     788             :     else
     789             :     {
     790           0 :         entry_count = self->sph_count;
     791           0 :         entries = self->sph_entries;
     792             :     }
     793             : 
     794           0 :     if (key_index < 0 || key_index >= entry_count)
     795           0 :         return NULL;
     796             :     else
     797           0 :         return entries[key_index]->key;
     798             : }
     799             : 
     800             : /*-----------------------------------------------------------------------------
     801             : 
     802             : Name:
     803             :     EnvisatFile_GetKeyValueAsString()
     804             : 
     805             : Purpose:
     806             :     Fetch the value associated with the indicated key as a string.
     807             : 
     808             : Description:
     809             : 
     810             : Inputs:
     811             :     self -- the file to be searched.
     812             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
     813             :     key -- the key (name) to be searched for.
     814             :     default_value -- the value to return if the key is not found.
     815             : 
     816             : Outputs:
     817             : 
     818             : Returns:
     819             :     pointer to value string, or default_value if not found.
     820             : 
     821             : -----------------------------------------------------------------------------*/
     822             : 
     823           0 : const char *EnvisatFile_GetKeyValueAsString(EnvisatFile *self,
     824             :                                             EnvisatFile_HeaderFlag mph_or_sph,
     825             :                                             const char *key,
     826             :                                             const char *default_value)
     827             : 
     828             : {
     829             :     int entry_count, key_index;
     830             :     EnvisatNameValue **entries;
     831             : 
     832             :     /*
     833             :      * Select source list.
     834             :      */
     835           0 :     if (mph_or_sph == MPH)
     836             :     {
     837           0 :         entry_count = self->mph_count;
     838           0 :         entries = self->mph_entries;
     839             :     }
     840             :     else
     841             :     {
     842           0 :         entry_count = self->sph_count;
     843           0 :         entries = self->sph_entries;
     844             :     }
     845             : 
     846             :     /*
     847             :      * Find and return the value.
     848             :      */
     849           0 :     key_index = S_NameValueList_FindKey(key, entry_count, entries);
     850           0 :     if (key_index == -1)
     851           0 :         return default_value;
     852             :     else
     853           0 :         return entries[key_index]->value;
     854             : }
     855             : 
     856             : /*-----------------------------------------------------------------------------
     857             : 
     858             : Name:
     859             :     EnvisatFile_SetKeyValueAsString()
     860             : 
     861             : Purpose:
     862             :     Set the value associated with the indicated key as a string.
     863             : 
     864             : Description:
     865             : 
     866             : Inputs:
     867             :     self -- the file to be searched.
     868             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
     869             :     key -- the key (name) to be searched for.
     870             :     value -- the value to assign.
     871             : 
     872             : Outputs:
     873             : 
     874             : Returns:
     875             :     SUCCESS or FAILURE.
     876             : 
     877             : -----------------------------------------------------------------------------*/
     878             : 
     879           0 : int EnvisatFile_SetKeyValueAsString(EnvisatFile *self,
     880             :                                     EnvisatFile_HeaderFlag mph_or_sph,
     881             :                                     const char *key, const char *value)
     882             : 
     883             : {
     884             :     int entry_count, key_index;
     885             :     EnvisatNameValue **entries;
     886             :     size_t nValueLen;
     887             :     size_t nEntryValueLen;
     888             : 
     889           0 :     if (!self->updatable)
     890             :     {
     891           0 :         SendError("File not opened for update access.");
     892           0 :         return FAILURE;
     893             :     }
     894             : 
     895             :     /*
     896             :      * Select source list.
     897             :      */
     898           0 :     if (mph_or_sph == MPH)
     899             :     {
     900           0 :         entry_count = self->mph_count;
     901           0 :         entries = self->mph_entries;
     902             :     }
     903             :     else
     904             :     {
     905           0 :         entry_count = self->sph_count;
     906           0 :         entries = self->sph_entries;
     907             :     }
     908             : 
     909             :     /*
     910             :      * Find and return the value.
     911             :      */
     912           0 :     key_index = S_NameValueList_FindKey(key, entry_count, entries);
     913           0 :     if (key_index == -1)
     914             :     {
     915             :         char error_buf[2048];
     916             : 
     917           0 :         snprintf(error_buf, sizeof(error_buf),
     918             :                  "Unable to set header field \"%s\", field not found.", key);
     919             : 
     920           0 :         SendError(error_buf);
     921           0 :         return FAILURE;
     922             :     }
     923             : 
     924           0 :     self->header_dirty = 1;
     925           0 :     nValueLen = strlen(value);
     926           0 :     nEntryValueLen = strlen(entries[key_index]->value);
     927           0 :     if (nValueLen >= nEntryValueLen)
     928             :     {
     929           0 :         memcpy(entries[key_index]->value, value, nEntryValueLen);
     930             :     }
     931             :     else
     932             :     {
     933           0 :         memcpy(entries[key_index]->value, value, nValueLen);
     934           0 :         memset(entries[key_index]->value + nValueLen, ' ',
     935             :                nEntryValueLen - nValueLen);
     936             :     }
     937             : 
     938           0 :     return SUCCESS;
     939             : }
     940             : 
     941             : /*-----------------------------------------------------------------------------
     942             : 
     943             : Name:
     944             :     EnvisatFile_GetKeyValueAsInt()
     945             : 
     946             : Purpose:
     947             :     Fetch the value associated with the indicated key as an integer.
     948             : 
     949             : Description:
     950             : 
     951             : Inputs:
     952             :     self -- the file to be searched.
     953             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
     954             :     key -- the key (name) to be searched for.
     955             :     default_value -- the value to return if the key is not found.
     956             : 
     957             : Outputs:
     958             : 
     959             : Returns:
     960             :     key value, or default_value if key not found.
     961             : 
     962             : -----------------------------------------------------------------------------*/
     963             : 
     964           0 : int EnvisatFile_GetKeyValueAsInt(EnvisatFile *self,
     965             :                                  EnvisatFile_HeaderFlag mph_or_sph,
     966             :                                  const char *key, int default_value)
     967             : 
     968             : {
     969             :     int entry_count, key_index;
     970             :     EnvisatNameValue **entries;
     971             : 
     972             :     /*
     973             :      * Select source list.
     974             :      */
     975           0 :     if (mph_or_sph == MPH)
     976             :     {
     977           0 :         entry_count = self->mph_count;
     978           0 :         entries = self->mph_entries;
     979             :     }
     980             :     else
     981             :     {
     982           0 :         entry_count = self->sph_count;
     983           0 :         entries = self->sph_entries;
     984             :     }
     985             : 
     986             :     /*
     987             :      * Find and return the value.
     988             :      */
     989           0 :     key_index = S_NameValueList_FindKey(key, entry_count, entries);
     990           0 :     if (key_index == -1)
     991           0 :         return default_value;
     992             :     else
     993           0 :         return atoi(entries[key_index]->value);
     994             : }
     995             : 
     996             : /*-----------------------------------------------------------------------------
     997             : 
     998             : Name:
     999             :     EnvisatFile_SetKeyValueAsInt()
    1000             : 
    1001             : Purpose:
    1002             :     Set the value associated with the indicated key as an integer.
    1003             : 
    1004             : Description:
    1005             : 
    1006             : Inputs:
    1007             :     self -- the file to be searched.
    1008             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
    1009             :     key -- the key (name) to be searched for.
    1010             :     value -- the value to assign.
    1011             : 
    1012             : Outputs:
    1013             : 
    1014             : Returns:
    1015             :     SUCCESS or FAILURE.
    1016             : 
    1017             : -----------------------------------------------------------------------------*/
    1018             : 
    1019           0 : int EnvisatFile_SetKeyValueAsInt(EnvisatFile *self,
    1020             :                                  EnvisatFile_HeaderFlag mph_or_sph,
    1021             :                                  const char *key, int value)
    1022             : 
    1023             : {
    1024             :     char format[32], string_value[128];
    1025             :     const char *prototype_value;
    1026             : 
    1027             :     prototype_value =
    1028           0 :         EnvisatFile_GetKeyValueAsString(self, mph_or_sph, key, NULL);
    1029           0 :     if (prototype_value == NULL)
    1030             :     {
    1031             :         char error_buf[2048];
    1032             : 
    1033           0 :         snprintf(error_buf, sizeof(error_buf),
    1034             :                  "Unable to set header field \"%s\", field not found.", key);
    1035             : 
    1036           0 :         SendError(error_buf);
    1037           0 :         return FAILURE;
    1038             :     }
    1039             : 
    1040           0 :     snprintf(format, sizeof(format), "%%+0%dd", (int)strlen(prototype_value));
    1041           0 :     snprintf(string_value, sizeof(string_value), format, value);
    1042             : 
    1043           0 :     return EnvisatFile_SetKeyValueAsString(self, mph_or_sph, key, string_value);
    1044             : }
    1045             : 
    1046             : /*-----------------------------------------------------------------------------
    1047             : 
    1048             : Name:
    1049             :     EnvisatFile_GetKeyValueAsDouble()
    1050             : 
    1051             : Purpose:
    1052             :     Fetch the value associated with the indicated key as a double.
    1053             : 
    1054             : Description:
    1055             : 
    1056             : Inputs:
    1057             :     self -- the file to be searched.
    1058             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
    1059             :     key -- the key (name) to be searched for.
    1060             :     default_value -- the value to return if the key is not found.
    1061             : 
    1062             : Outputs:
    1063             : 
    1064             : Returns:
    1065             :     key value, or default_value if key not found.
    1066             : 
    1067             : -----------------------------------------------------------------------------*/
    1068             : 
    1069           0 : double EnvisatFile_GetKeyValueAsDouble(EnvisatFile *self,
    1070             :                                        EnvisatFile_HeaderFlag mph_or_sph,
    1071             :                                        const char *key, double default_value)
    1072             : 
    1073             : {
    1074             :     int entry_count, key_index;
    1075             :     EnvisatNameValue **entries;
    1076             : 
    1077             :     /*
    1078             :      * Select source list.
    1079             :      */
    1080           0 :     if (mph_or_sph == MPH)
    1081             :     {
    1082           0 :         entry_count = self->mph_count;
    1083           0 :         entries = self->mph_entries;
    1084             :     }
    1085             :     else
    1086             :     {
    1087           0 :         entry_count = self->sph_count;
    1088           0 :         entries = self->sph_entries;
    1089             :     }
    1090             : 
    1091             :     /*
    1092             :      * Find and return the value.
    1093             :      */
    1094           0 :     key_index = S_NameValueList_FindKey(key, entry_count, entries);
    1095           0 :     if (key_index == -1)
    1096           0 :         return default_value;
    1097             :     else
    1098           0 :         return atof(entries[key_index]->value);
    1099             : }
    1100             : 
    1101             : /*-----------------------------------------------------------------------------
    1102             : 
    1103             : Name:
    1104             :     EnvisatFile_SetKeyValueAsDouble()
    1105             : 
    1106             : Purpose:
    1107             :     Set the value associated with the indicated key as a double.
    1108             : 
    1109             : Description:
    1110             :     Note that this function attempts to format the new value similarly to
    1111             :     the previous value.  In some cases (especially exponential values) this
    1112             :     may not work out well.  In case of problems the caller is encourage to
    1113             :     format the value themselves, and use the EnvisatFile_SetKeyValueAsString
    1114             :     function, but taking extreme care about the string length.
    1115             : 
    1116             : Inputs:
    1117             :     self -- the file to be searched.
    1118             :     mph_or_sph -- Either MPH or SPH depending on the header to be searched.
    1119             :     key -- the key (name) to be searched for.
    1120             :     value -- the value to assign.
    1121             : 
    1122             : Outputs:
    1123             : 
    1124             : Returns:
    1125             :     SUCCESS or FAILURE.
    1126             : 
    1127             : -----------------------------------------------------------------------------*/
    1128             : 
    1129           0 : int EnvisatFile_SetKeyValueAsDouble(EnvisatFile *self,
    1130             :                                     EnvisatFile_HeaderFlag mph_or_sph,
    1131             :                                     const char *key, double value)
    1132             : 
    1133             : {
    1134             :     char format[32], string_value[128];
    1135             :     const char *prototype_value;
    1136             :     int length;
    1137             : 
    1138             :     prototype_value =
    1139           0 :         EnvisatFile_GetKeyValueAsString(self, mph_or_sph, key, NULL);
    1140           0 :     if (prototype_value == NULL)
    1141             :     {
    1142             :         char error_buf[2048];
    1143             : 
    1144           0 :         snprintf(error_buf, sizeof(error_buf),
    1145             :                  "Unable to set header field \"%s\", field not found.", key);
    1146             : 
    1147           0 :         SendError(error_buf);
    1148           0 :         return FAILURE;
    1149             :     }
    1150             : 
    1151           0 :     length = (int)strlen(prototype_value);
    1152           0 :     if (prototype_value[length - 4] == 'E')
    1153             :     {
    1154           0 :         snprintf(format, sizeof(format), "%%+%dE", length - 4);
    1155           0 :         snprintf(string_value, sizeof(string_value), format, value);
    1156             :     }
    1157             :     else
    1158             :     {
    1159           0 :         int decimals = 0, i;
    1160           0 :         for (i = length - 1; i > 0; i--)
    1161             :         {
    1162           0 :             if (prototype_value[i] == '.')
    1163           0 :                 break;
    1164             : 
    1165           0 :             decimals++;
    1166             :         }
    1167             : 
    1168           0 :         snprintf(format, sizeof(format), "%%+0%d.%df", length, decimals);
    1169           0 :         CPLsnprintf(string_value, sizeof(string_value), format, value);
    1170             : 
    1171           0 :         if ((int)strlen(string_value) > length)
    1172           0 :             string_value[length] = '\0';
    1173             :     }
    1174             : 
    1175           0 :     return EnvisatFile_SetKeyValueAsString(self, mph_or_sph, key, string_value);
    1176             : }
    1177             : 
    1178             : /*-----------------------------------------------------------------------------
    1179             : 
    1180             : Name:
    1181             :     EnvisatFile_GetDatasetIndex()
    1182             : 
    1183             : Purpose:
    1184             :     Fetch the dataset index given a dataset name.
    1185             : 
    1186             : Description:
    1187             :     The provided name is extended with spaces, so it isn't necessary for the
    1188             :     application to pass all the passing spaces.
    1189             : 
    1190             : Inputs:
    1191             :     self -- the file to be searched.
    1192             :     ds_name -- the name (DS_NAME) of the dataset to find.
    1193             : 
    1194             : Outputs:
    1195             : 
    1196             : Returns:
    1197             :     Dataset index that matches, or -1 if none found.
    1198             : 
    1199             : -----------------------------------------------------------------------------*/
    1200             : 
    1201           0 : int EnvisatFile_GetDatasetIndex(EnvisatFile *self, const char *ds_name)
    1202             : 
    1203             : {
    1204             :     int i;
    1205             :     char padded_ds_name[100];
    1206             : 
    1207             :     /*
    1208             :      * Padd the name.  While the normal product spec says the DS_NAME will
    1209             :      * be 28 characters, I try to pad more than this in case the specification
    1210             :      * is changed.
    1211             :      */
    1212           0 :     strncpy(padded_ds_name, ds_name, sizeof(padded_ds_name));
    1213           0 :     padded_ds_name[sizeof(padded_ds_name) - 1] = 0;
    1214           0 :     for (i = (int)strlen(padded_ds_name);
    1215           0 :          (size_t)i < sizeof(padded_ds_name) - 1; i++)
    1216             :     {
    1217           0 :         padded_ds_name[i] = ' ';
    1218             :     }
    1219           0 :     padded_ds_name[i] = '\0';
    1220             : 
    1221             :     /*
    1222             :      * Compare only for the full length of DS_NAME we have saved.
    1223             :      */
    1224           0 :     for (i = 0; i < self->ds_count; i++)
    1225             :     {
    1226           0 :         if (strncmp(padded_ds_name, self->ds_info[i]->ds_name,
    1227           0 :                     strlen(self->ds_info[i]->ds_name)) == 0)
    1228             :         {
    1229           0 :             return i;
    1230             :         }
    1231             :     }
    1232             : 
    1233           0 :     return -1;
    1234             : }
    1235             : 
    1236             : /*-----------------------------------------------------------------------------
    1237             : 
    1238             : Name:
    1239             :     EnvisatFile_GetDatasetInfo()
    1240             : 
    1241             : Purpose:
    1242             :     Fetch the information associated with a dataset definition.
    1243             : 
    1244             : Description:
    1245             :     The returned strings are pointers to internal copies, and should not be
    1246             :     modified, or freed.  Note, any of the "output" parameters can safely be
    1247             :     NULL if it is not needed.
    1248             : 
    1249             : Inputs:
    1250             :     self -- the file to be searched.
    1251             :     ds_index -- the dataset index to fetch
    1252             : 
    1253             : Outputs:
    1254             :     ds_name -- the dataset symbolic name, i.e 'MDS1 SQ ADS              '.
    1255             :     ds_type -- the dataset type, i.e. 'A', not sure of valid values.
    1256             :     filename -- dataset filename, normally spaces, or 'NOT USED          '.
    1257             :     ds_offset -- the byte offset in the whole file to the first byte of
    1258             :                  dataset data.  This is 0 for unused datasets.
    1259             :     ds_size -- the size, in bytes, of the whole dataset.
    1260             :     num_dsr -- the number of records in the dataset.
    1261             :     dsr_size -- the size of one record in the dataset in bytes, -1 if
    1262             :                 records are variable sized.
    1263             : 
    1264             : Returns:
    1265             :     SUCCESS if dataset exists, or FAILURE if ds_index is out of range.
    1266             : 
    1267             : -----------------------------------------------------------------------------*/
    1268             : 
    1269           0 : int EnvisatFile_GetDatasetInfo(EnvisatFile *self, int ds_index,
    1270             :                                const char **ds_name, const char **ds_type,
    1271             :                                const char **filename, int *ds_offset,
    1272             :                                int *ds_size, int *num_dsr, int *dsr_size)
    1273             : 
    1274             : {
    1275           0 :     if (ds_index < 0 || ds_index >= self->ds_count)
    1276           0 :         return FAILURE;
    1277             : 
    1278           0 :     if (ds_name != NULL)
    1279           0 :         *ds_name = self->ds_info[ds_index]->ds_name;
    1280           0 :     if (ds_type != NULL)
    1281           0 :         *ds_type = self->ds_info[ds_index]->ds_type;
    1282           0 :     if (filename != NULL)
    1283           0 :         *filename = self->ds_info[ds_index]->filename;
    1284           0 :     if (ds_offset != NULL)
    1285           0 :         *ds_offset = self->ds_info[ds_index]->ds_offset;
    1286           0 :     if (ds_size != NULL)
    1287           0 :         *ds_size = self->ds_info[ds_index]->ds_size;
    1288           0 :     if (num_dsr != NULL)
    1289           0 :         *num_dsr = self->ds_info[ds_index]->num_dsr;
    1290           0 :     if (dsr_size != NULL)
    1291           0 :         *dsr_size = self->ds_info[ds_index]->dsr_size;
    1292             : 
    1293           0 :     return SUCCESS;
    1294             : }
    1295             : 
    1296             : /*-----------------------------------------------------------------------------
    1297             : 
    1298             : Name:
    1299             :     EnvisatFile_SetDatasetInfo()
    1300             : 
    1301             : Purpose:
    1302             :     Update the information associated with a dataset definition.
    1303             : 
    1304             : Description:
    1305             : 
    1306             : Inputs:
    1307             :     self -- the file to be searched.
    1308             :     ds_index -- the dataset index to fetch
    1309             :     ds_offset -- the byte offset in the whole file to the first byte of
    1310             :                  dataset data.  This is 0 for unused datasets.
    1311             :     ds_size -- the size, in bytes, of the whole dataset.
    1312             :     num_dsr -- the number of records in the dataset.
    1313             :     dsr_size -- the size of one record in the dataset in bytes, -1 if
    1314             :                 records are variable sized.
    1315             : 
    1316             : Outputs:
    1317             : 
    1318             : Returns:
    1319             :     SUCCESS or FAILURE.
    1320             : 
    1321             : -----------------------------------------------------------------------------*/
    1322             : 
    1323           0 : int EnvisatFile_SetDatasetInfo(EnvisatFile *self, int ds_index, int ds_offset,
    1324             :                                int ds_size, int num_dsr, int dsr_size)
    1325             : 
    1326             : {
    1327           0 :     if (ds_index < 0 || ds_index >= self->ds_count)
    1328           0 :         return FAILURE;
    1329             : 
    1330           0 :     self->ds_info[ds_index]->ds_offset = ds_offset;
    1331           0 :     self->ds_info[ds_index]->ds_size = ds_size;
    1332           0 :     self->ds_info[ds_index]->num_dsr = num_dsr;
    1333           0 :     self->ds_info[ds_index]->dsr_size = dsr_size;
    1334           0 :     self->header_dirty = 1;
    1335             : 
    1336           0 :     return SUCCESS;
    1337             : }
    1338             : 
    1339             : /*-----------------------------------------------------------------------------
    1340             : 
    1341             : Name:
    1342             :     EnvisatFile_ReadDatasetChunk()
    1343             : 
    1344             : Purpose:
    1345             :     Read an arbitrary chunk of a dataset.
    1346             : 
    1347             : Description:
    1348             :     Note that no range checking is made on offset and size, and data may be
    1349             :     read from outside the dataset if they are inappropriate.
    1350             : 
    1351             : Inputs:
    1352             :     self -- the file to be searched.
    1353             :     ds_index -- the index of dataset to access.
    1354             :     offset -- byte offset within database to read.
    1355             :     size -- size of buffer to fill in bytes.
    1356             :     buffer -- buffer to load data into
    1357             : 
    1358             : Outputs:
    1359             :     buffer is updated on SUCCESS.
    1360             : 
    1361             : Returns:
    1362             :     SUCCESS or FAILURE
    1363             : 
    1364             : -----------------------------------------------------------------------------*/
    1365             : 
    1366           0 : int EnvisatFile_ReadDatasetChunk(EnvisatFile *self, int ds_index, int offset,
    1367             :                                  int size, void *buffer)
    1368             : 
    1369             : {
    1370           0 :     if (ds_index < 0 || ds_index >= self->ds_count)
    1371             :     {
    1372           0 :         SendError("Attempt to read non-existent dataset in "
    1373             :                   "EnvisatFile_ReadDatasetChunk()");
    1374           0 :         return FAILURE;
    1375             :     }
    1376             : 
    1377           0 :     if (offset < 0 || offset + size > self->ds_info[ds_index]->ds_size)
    1378             :     {
    1379           0 :         SendError("Attempt to read beyond end of dataset in "
    1380             :                   "EnvisatFile_ReadDatasetChunk()");
    1381           0 :         return FAILURE;
    1382             :     }
    1383             : 
    1384           0 :     if (VSIFSeekL(self->fp, self->ds_info[ds_index]->ds_offset + offset,
    1385             :                   SEEK_SET) != 0)
    1386             :     {
    1387           0 :         SendError("seek failed in EnvisatFile_ReadChunk()");
    1388           0 :         return FAILURE;
    1389             :     }
    1390             : 
    1391           0 :     if ((int)VSIFReadL(buffer, 1, size, self->fp) != size)
    1392             :     {
    1393           0 :         SendError("read failed in EnvisatFile_ReadChunk()");
    1394           0 :         return FAILURE;
    1395             :     }
    1396             : 
    1397           0 :     return SUCCESS;
    1398             : }
    1399             : 
    1400             : /*-----------------------------------------------------------------------------
    1401             : 
    1402             : Name:
    1403             :     EnvisatFile_WriteDatasetRecord()
    1404             : 
    1405             : Purpose:
    1406             :     Write an arbitrary dataset record.
    1407             : 
    1408             : Description:
    1409             :     Note that no range checking is made on offset and size, and data may be
    1410             :     read from outside the dataset if they are inappropriate.
    1411             : 
    1412             : Inputs:
    1413             :     self -- the file to be searched.
    1414             :     ds_index -- the index of dataset to access.
    1415             :     record_index -- the record to write.
    1416             :     record_buffer -- buffer to load data into
    1417             : 
    1418             : Outputs:
    1419             : 
    1420             : Returns:
    1421             :     SUCCESS or FAILURE
    1422             : 
    1423             : -----------------------------------------------------------------------------*/
    1424             : 
    1425           0 : int EnvisatFile_WriteDatasetRecord(EnvisatFile *self, int ds_index,
    1426             :                                    int record_index, void *buffer)
    1427             : 
    1428             : {
    1429             :     int absolute_offset;
    1430             :     int result;
    1431             : 
    1432           0 :     if (ds_index < 0 || ds_index >= self->ds_count)
    1433             :     {
    1434           0 :         SendError("Attempt to write non-existent dataset in "
    1435             :                   "EnvisatFile_WriteDatasetRecord()");
    1436           0 :         return FAILURE;
    1437             :     }
    1438             : 
    1439           0 :     if (record_index < 0 || record_index >= self->ds_info[ds_index]->num_dsr)
    1440             :     {
    1441           0 :         SendError("Attempt to write beyond end of dataset in "
    1442             :                   "EnvisatFile_WriteDatasetRecord()");
    1443           0 :         return FAILURE;
    1444             :     }
    1445             : 
    1446           0 :     absolute_offset = self->ds_info[ds_index]->ds_offset +
    1447           0 :                       record_index * self->ds_info[ds_index]->dsr_size;
    1448             : 
    1449           0 :     if (VSIFSeekL(self->fp, absolute_offset, SEEK_SET) != 0)
    1450             :     {
    1451           0 :         SendError("seek failed in EnvisatFile_WriteDatasetRecord()");
    1452           0 :         return FAILURE;
    1453             :     }
    1454             : 
    1455           0 :     result =
    1456           0 :         (int)VSIFWriteL(buffer, 1, self->ds_info[ds_index]->dsr_size, self->fp);
    1457           0 :     if (result != self->ds_info[ds_index]->dsr_size)
    1458             :     {
    1459           0 :         SendError("write failed in EnvisatFile_WriteDatasetRecord()");
    1460           0 :         return FAILURE;
    1461             :     }
    1462             : 
    1463           0 :     return SUCCESS;
    1464             : }
    1465             : 
    1466             : /*-----------------------------------------------------------------------------
    1467             : 
    1468             : Name:
    1469             :     EnvisatFile_ReadDatasetRecord()
    1470             : 
    1471             : Purpose:
    1472             :     Read an arbitrary dataset record.
    1473             : 
    1474             : Description:
    1475             :     Note that no range checking is made on offset and size, and data may be
    1476             :     read from outside the dataset if they are inappropriate.
    1477             : 
    1478             : Inputs:
    1479             :     self -- the file to be searched.
    1480             :     ds_index -- the index of dataset to access.
    1481             :     record_index -- the record to write.
    1482             :     record_buffer -- buffer to load data into
    1483             : 
    1484             : Outputs:
    1485             : 
    1486             : Returns:
    1487             :     SUCCESS or FAILURE
    1488             : 
    1489             : -----------------------------------------------------------------------------*/
    1490             : 
    1491             : int EnvisatFile_ReadDatasetRecordChunk(EnvisatFile *, int, int, void *, int,
    1492             :                                        int);
    1493             : 
    1494           0 : int EnvisatFile_ReadDatasetRecord(EnvisatFile *self, int ds_index,
    1495             :                                   int record_index, void *buffer)
    1496             : {
    1497           0 :     return EnvisatFile_ReadDatasetRecordChunk(self, ds_index, record_index,
    1498             :                                               buffer, 0, -1);
    1499             : }
    1500             : 
    1501             : /*-----------------------------------------------------------------------------
    1502             : 
    1503             : Name:
    1504             :     EnvisatFile_ReadDatasetRecordChunk()
    1505             : 
    1506             : Purpose:
    1507             :     Read a part of an arbitrary dataset record.
    1508             : 
    1509             : Description:
    1510             :     Note that no range checking is made on dataset's offset and size,
    1511             :     and data may be read from outside the dataset if they are inappropriate.
    1512             : 
    1513             : Inputs:
    1514             :     self -- the file to be searched.
    1515             :     ds_index -- the index of dataset to access.
    1516             :     record_index -- the record to write.
    1517             :     record_buffer -- buffer to load data into
    1518             :     offset -- chunk offset relative to the record start (zerro offset)
    1519             :     size -- chunk size (set -1 to read from offset to the records' end)
    1520             : 
    1521             : Outputs:
    1522             : 
    1523             : Returns:
    1524             :     SUCCESS or FAILURE
    1525             : 
    1526             : -----------------------------------------------------------------------------*/
    1527             : 
    1528           0 : int EnvisatFile_ReadDatasetRecordChunk(EnvisatFile *self, int ds_index,
    1529             :                                        int record_index, void *buffer,
    1530             :                                        int offset, int size)
    1531             : {
    1532             :     int absolute_offset;
    1533             :     int result;
    1534           0 :     int dsr_size = self->ds_info[ds_index]->dsr_size;
    1535             : 
    1536           0 :     if ((offset < 0) || (offset > dsr_size))
    1537             :     {
    1538           0 :         SendError("Invalid chunk offset in "
    1539             :                   "EnvisatFile_ReadDatasetRecordChunk()");
    1540           0 :         return FAILURE;
    1541             :     }
    1542             : 
    1543           0 :     if (size < 0)
    1544           0 :         size = dsr_size - offset;
    1545             : 
    1546           0 :     if (ds_index < 0 || ds_index >= self->ds_count)
    1547             :     {
    1548           0 :         SendError("Attempt to read non-existent dataset in "
    1549             :                   "EnvisatFile_ReadDatasetRecordChunk()");
    1550           0 :         return FAILURE;
    1551             :     }
    1552             : 
    1553           0 :     if (record_index < 0 || record_index >= self->ds_info[ds_index]->num_dsr)
    1554             :     {
    1555           0 :         SendError("Attempt to read beyond end of dataset in "
    1556             :                   "EnvisatFile_ReadDatasetRecordChunk()");
    1557           0 :         return FAILURE;
    1558             :     }
    1559             : 
    1560           0 :     if ((offset + size) > dsr_size)
    1561             :     {
    1562           0 :         SendError("Attempt to read beyond the record's boundary"
    1563             :                   "EnvisatFile_ReadDatasetRecord()");
    1564           0 :         return FAILURE;
    1565             :     }
    1566             : 
    1567           0 :     absolute_offset =
    1568           0 :         self->ds_info[ds_index]->ds_offset + record_index * dsr_size + offset;
    1569             : 
    1570           0 :     if (VSIFSeekL(self->fp, absolute_offset, SEEK_SET) != 0)
    1571             :     {
    1572           0 :         SendError("seek failed in EnvisatFile_ReadDatasetRecordChunk()");
    1573           0 :         return FAILURE;
    1574             :     }
    1575             : 
    1576           0 :     result = (int)VSIFReadL(buffer, 1, size, self->fp);
    1577           0 :     if (result != size)
    1578             :     {
    1579           0 :         SendError("read failed in EnvisatFile_ReadDatasetRecord()");
    1580           0 :         return FAILURE;
    1581             :     }
    1582             : 
    1583           0 :     return SUCCESS;
    1584             : }
    1585             : 
    1586             : /*-----------------------------------------------------------------------------
    1587             : 
    1588             : Name:
    1589             :     S_NameValueList_FindKey()
    1590             : 
    1591             : Purpose:
    1592             :     Search for given key in list of name/value pairs.
    1593             : 
    1594             : Description:
    1595             :     Scans list looking for index of EnvisatNameValue where the key matches
    1596             :     (case sensitive) the passed in name.
    1597             : 
    1598             : Inputs:
    1599             :     key -- the key, such as "SLICE_POSITION" being searched for.
    1600             :     entry_count -- the number of items in the entries array.
    1601             :     entries -- array of name/value structures to search.
    1602             : 
    1603             : Outputs:
    1604             : 
    1605             : Returns:
    1606             :     array index into entries, or -1 on failure.
    1607             : 
    1608             : -----------------------------------------------------------------------------*/
    1609             : 
    1610           0 : int S_NameValueList_FindKey(const char *key, int entry_count,
    1611             :                             EnvisatNameValue **entries)
    1612             : 
    1613             : {
    1614             :     int i;
    1615             : 
    1616           0 :     for (i = 0; i < entry_count; i++)
    1617             :     {
    1618           0 :         if (strcmp(entries[i]->key, key) == 0)
    1619           0 :             return i;
    1620             :     }
    1621             : 
    1622           0 :     return -1;
    1623             : }
    1624             : 
    1625             : /*-----------------------------------------------------------------------------
    1626             : 
    1627             : Name:
    1628             :     S_NameValueList_FindValue()
    1629             : 
    1630             : Purpose:
    1631             :     Search for given key in list of name/value pairs, and return value.
    1632             : 
    1633             : Description:
    1634             :     Returns value string or default if key not found.
    1635             : 
    1636             : Inputs:
    1637             :     key -- the key, such as "SLICE_POSITION" being searched for.
    1638             :     entry_count -- the number of items in the entries array.
    1639             :     entries -- array of name/value structures to search.
    1640             :     default_value -- value to use if key not found.
    1641             : 
    1642             : Outputs:
    1643             : 
    1644             : Returns:
    1645             :     value string, or default if key not found.
    1646             : 
    1647             : -----------------------------------------------------------------------------*/
    1648             : 
    1649           0 : const char *S_NameValueList_FindValue(const char *key, int entry_count,
    1650             :                                       EnvisatNameValue **entries,
    1651             :                                       const char *default_value)
    1652             : 
    1653             : {
    1654             :     int i;
    1655             : 
    1656           0 :     i = S_NameValueList_FindKey(key, entry_count, entries);
    1657           0 :     if (i == -1)
    1658           0 :         return default_value;
    1659             :     else
    1660           0 :         return entries[i]->value;
    1661             : }
    1662             : 
    1663             : /*-----------------------------------------------------------------------------
    1664             : 
    1665             : Name:
    1666             :     S_NameValueList_Parse()
    1667             : 
    1668             : Purpose:
    1669             :     Parse a block of envisat style name/value pairs into an
    1670             :     EnvisatNameValue structure list.
    1671             : 
    1672             : Description:
    1673             :     The passed in text block should be zero terminated.  The entry_count,
    1674             :     and entries should be pre-initialized (normally to 0 and NULL).
    1675             : 
    1676             : Inputs:
    1677             :     text -- the block of text, multiple lines, to be processed.
    1678             : 
    1679             : Outputs:
    1680             :     entry_count -- returns with the updated number of entries in the
    1681             :                    entries array.
    1682             :     entries -- returns with updated array info structures.
    1683             : 
    1684             : Returns:
    1685             :     SUCCESS or FAILURE
    1686             : 
    1687             : -----------------------------------------------------------------------------*/
    1688             : 
    1689           0 : int S_NameValueList_Parse(const char *text, int text_offset, int *entry_count,
    1690             :                           EnvisatNameValue ***entries)
    1691             : 
    1692             : {
    1693           0 :     const char *next_text = text;
    1694             : 
    1695             :     /*
    1696             :      * Loop over each input line in the text block.
    1697             :      */
    1698           0 :     while (*next_text != '\0')
    1699             :     {
    1700             :         char line[1024];
    1701           0 :         int line_len = 0;
    1702           0 :         int equal_index = 0;
    1703           0 :         int src_char = 0;
    1704           0 :         int line_offset = 0;
    1705           0 :         EnvisatNameValue *entry = NULL;
    1706             :         /* workaround cppcheck false positive by using a pointer */
    1707           0 :         char *pszLine = line;
    1708             : 
    1709             :         /*
    1710             :          * Extract one line of text into the "line" buffer, and remove the
    1711             :          * newline character.  Eat leading spaces.
    1712             :          */
    1713           0 :         while (*next_text == ' ')
    1714             :         {
    1715           0 :             next_text++;
    1716             :         }
    1717           0 :         line_offset = (int)(next_text - text) + text_offset;
    1718           0 :         while (*next_text != '\0' && *next_text != '\n')
    1719             :         {
    1720           0 :             if (line_len > ((int)sizeof(line) - 2))
    1721             :             {
    1722           0 :                 SendError("S_NameValueList_Parse(): "
    1723             :                           "Corrupt line, longer than 1024 characters.");
    1724           0 :                 return FAILURE;
    1725             :             }
    1726             : 
    1727           0 :             pszLine[line_len++] = *(next_text++);
    1728             :         }
    1729             : 
    1730           0 :         pszLine[line_len] = '\0';
    1731           0 :         if (*next_text == '\n')
    1732           0 :             next_text++;
    1733             : 
    1734             :         /*
    1735             :          * Blank lines are permitted.  We will skip processing of any line
    1736             :          * that doesn't have an equal sign, under the assumption it is
    1737             :          * white space.
    1738             :          */
    1739           0 :         if (strstr(line, "=") == NULL)
    1740           0 :             continue;
    1741             : 
    1742             :         /*
    1743             :          * Create the name/value info structure.
    1744             :          */
    1745           0 :         entry = (EnvisatNameValue *)CPLCalloc(sizeof(EnvisatNameValue), 1);
    1746           0 :         entry->literal_line = CPLStrdup(line);
    1747             : 
    1748             :         /*
    1749             :          * Capture the key.  We take everything up to the equal sign.  There
    1750             :          * should not be any white space, but if so, we take it as part of the
    1751             :          * key.
    1752             :          */
    1753           0 :         equal_index = (int)(strstr(line, "=") - line);
    1754           0 :         entry->key = (char *)CPLMalloc(equal_index + 1);
    1755           0 :         strncpy(entry->key, line, equal_index);
    1756           0 :         entry->key[equal_index] = '\0';
    1757           0 :         entry->value_offset = line_offset + equal_index + 1;
    1758             : 
    1759             :         /*
    1760             :          * If the next character after the equal sign is a double quote, then
    1761             :          * the value is a string.  Suck out the text between the double quotes.
    1762             :          */
    1763           0 :         if (line[equal_index + 1] == '"')
    1764             :         {
    1765           0 :             for (src_char = equal_index + 2;
    1766           0 :                  line[src_char] != '\0' && line[src_char] != '"'; src_char++)
    1767             :             {
    1768             :             }
    1769             : 
    1770           0 :             line[src_char] = '\0';
    1771           0 :             entry->value = CPLStrdup(line + equal_index + 2);
    1772           0 :             entry->value_len = strlen(entry->value) + 1;
    1773           0 :             entry->value_offset += 1;
    1774             :         }
    1775             : 
    1776             :         /*
    1777             :          * The value is numeric, and may include a units field.
    1778             :          */
    1779             :         else
    1780             :         {
    1781           0 :             for (src_char = equal_index + 1;
    1782           0 :                  line[src_char] != '\0' && line[src_char] != '<' &&
    1783           0 :                  line[src_char] != ' ';
    1784           0 :                  src_char++)
    1785             :             {
    1786             :             }
    1787             : 
    1788             :             /* capture units */
    1789           0 :             if (line[src_char] == '<')
    1790             :             {
    1791             :                 int dst_char;
    1792             : 
    1793           0 :                 for (dst_char = src_char + 1;
    1794           0 :                      line[dst_char] != '>' && line[dst_char] != '\0';
    1795           0 :                      dst_char++)
    1796             :                 {
    1797             :                 }
    1798             : 
    1799           0 :                 line[dst_char] = '\0';
    1800           0 :                 entry->units = CPLStrdup(line + src_char + 1);
    1801             :             }
    1802             : 
    1803           0 :             line[src_char] = '\0';
    1804           0 :             entry->value = CPLStrdup(line + equal_index + 1);
    1805           0 :             entry->value_len = strlen(entry->value) + 1;
    1806             :         }
    1807             : 
    1808             :         /*
    1809             :          * Add the entry to the name/value list.
    1810             :          */
    1811           0 :         (*entry_count)++;
    1812           0 :         *entries = (EnvisatNameValue **)CPLRealloc(
    1813           0 :             *entries, *entry_count * sizeof(EnvisatNameValue *));
    1814             : 
    1815           0 :         if (*entries == NULL)
    1816             :         {
    1817           0 :             *entry_count = 0;
    1818           0 :             CPLFree(entry);
    1819           0 :             return FAILURE;
    1820             :         }
    1821             : 
    1822           0 :         (*entries)[*entry_count - 1] = entry;
    1823             :     }
    1824             : 
    1825           0 :     return SUCCESS;
    1826             : }
    1827             : 
    1828             : /*-----------------------------------------------------------------------------
    1829             : 
    1830             : Name:
    1831             :     S_NameValueList_Rewrite()
    1832             : 
    1833             : Purpose:
    1834             :     Rewrite the values of a name/value list in the file.
    1835             : 
    1836             : Description:
    1837             : 
    1838             : Inputs:
    1839             :     fp -- the VSILFILE to operate on.
    1840             :     entry_count -- number of entries to write.
    1841             :     entries -- array of entry descriptions.
    1842             : 
    1843             : Returns:
    1844             :     SUCCESS or FAILURE
    1845             : 
    1846             : 
    1847             : -----------------------------------------------------------------------------*/
    1848             : 
    1849           0 : int S_NameValueList_Rewrite(VSILFILE *fp, int entry_count,
    1850             :                             EnvisatNameValue **entries)
    1851             : 
    1852             : {
    1853             :     int i;
    1854             : 
    1855           0 :     for (i = 0; i < entry_count; i++)
    1856             :     {
    1857           0 :         EnvisatNameValue *entry = entries[i];
    1858             : 
    1859           0 :         if (VSIFSeekL(fp, entry->value_offset, SEEK_SET) != 0)
    1860             :         {
    1861           0 :             SendError("VSIFSeekL() failed writing name/value list.");
    1862           0 :             return FAILURE;
    1863             :         }
    1864             : 
    1865           0 :         if (VSIFWriteL(entry->value, 1, strlen(entry->value), fp) !=
    1866           0 :             strlen(entry->value))
    1867             :         {
    1868           0 :             SendError("VSIFWriteL() failed writing name/value list.");
    1869           0 :             return FAILURE;
    1870             :         }
    1871             :     }
    1872             : 
    1873           0 :     return SUCCESS;
    1874             : }
    1875             : 
    1876             : /*-----------------------------------------------------------------------------
    1877             : 
    1878             : Name:
    1879             :     S_NameValueList_Destroy()
    1880             : 
    1881             : Purpose:
    1882             :     Free resources associated with a name/value list.
    1883             : 
    1884             : Description:
    1885             :     The count, and name/value list pointers are set to 0/NULL on completion.
    1886             : 
    1887             : Inputs:
    1888             :     entry_count -- returns with the updated number of entries in the
    1889             :                    entries array.
    1890             :     entries -- returns with updated array info structures.
    1891             : 
    1892             : Outputs:
    1893             :     entry_count -- Set to zero.
    1894             :     entries -- Sett o NULL.
    1895             : 
    1896             : Returns:
    1897             : 
    1898             : 
    1899             : -----------------------------------------------------------------------------*/
    1900             : 
    1901           0 : void S_NameValueList_Destroy(int *entry_count, EnvisatNameValue ***entries)
    1902             : 
    1903             : {
    1904             :     int i;
    1905             : 
    1906           0 :     for (i = 0; i < *entry_count; i++)
    1907             :     {
    1908           0 :         CPLFree((*entries)[i]->key);
    1909           0 :         CPLFree((*entries)[i]->value);
    1910           0 :         CPLFree((*entries)[i]->units);
    1911           0 :         CPLFree((*entries)[i]->literal_line);
    1912           0 :         CPLFree((*entries)[i]);
    1913             :     }
    1914             : 
    1915           0 :     CPLFree(*entries);
    1916             : 
    1917           0 :     *entry_count = 0;
    1918           0 :     *entries = NULL;
    1919           0 : }
    1920             : 
    1921             : /* EOF */

Generated by: LCOV version 1.14