Coverage Report

Created: 2025-07-23 09:13

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