Coverage Report

Created: 2026-09-26 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/ceos2/ceosrecipe.c
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  ASI CEOS Translator
4
 * Purpose:  CEOS field layout recipes.
5
 * Author:   Paul Lahaie, pjlahaie@atlsci.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2000, Atlantis Scientific Inc
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "ceos.h"
14
15
/* Array of Datatypes and their names/values */
16
17
typedef struct
18
{
19
    const char *String;
20
    int Type;
21
} CeosStringType_t;
22
23
typedef struct
24
{
25
    int (*function)(CeosSARVolume_t *volume, const void *token);
26
    const void *token;
27
    const char *name;
28
} RecipeFunctionData_t;
29
30
static const CeosStringType_t CeosDataType[] = {
31
    {"IU1", CEOS_TYP_UCHAR},
32
    {"IU2", CEOS_TYP_USHORT},
33
    {"UI1", CEOS_TYP_UCHAR},
34
    {"UI2", CEOS_TYP_USHORT},
35
    {"CI*2", CEOS_TYP_COMPLEX_CHAR},
36
    {"CI*4", CEOS_TYP_COMPLEX_SHORT},
37
    {"CIS4", CEOS_TYP_COMPLEX_SHORT},
38
    {"CI*8", CEOS_TYP_COMPLEX_LONG},
39
    {"C*8", CEOS_TYP_COMPLEX_FLOAT},
40
    {"R*4", CEOS_TYP_FLOAT},
41
    {NULL, 0}};
42
43
static const CeosStringType_t CeosInterleaveType[] = {{"BSQ", CEOS_IL_BAND},
44
                                                      {" BSQ", CEOS_IL_BAND},
45
                                                      {"BIL", CEOS_IL_LINE},
46
                                                      {" BIL", CEOS_IL_LINE},
47
                                                      {NULL, 0}};
48
49
#define IMAGE_OPT {63, 192, 18, 18}
50
#define IMAGE_JERS_OPT                                                         \
51
    {50, 192, 18, 18} /* Some JERS data uses this instead of IMAGE_OPT */
52
#define PROC_DATA_REC {50, 11, 18, 20}
53
#define PROC_DATA_REC_ALT {50, 11, 31, 20}
54
#define PROC_DATA_REC_ALT2 {50, 11, 31, 50}       /* Some cases of ERS 1, 2 */
55
#define PROC_DATA_REC_ALOS2_L1_1 {50, 10, 18, 20} /* ALOS2 L1.1 */
56
#define DATA_SET_SUMMARY {18, 10, 18, 20}
57
58
/* NOTE: This seems to be the generic recipe used for most things */
59
static const CeosRecipeType_t RadarSatRecipe[] = {
60
    {CEOS_REC_NUMCHANS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 233, 4,
61
     CEOS_REC_TYP_I}, /* Number of channels */
62
    {CEOS_REC_INTERLEAVE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 269, 4,
63
     CEOS_REC_TYP_A}, /* Interleaving type */
64
    {CEOS_REC_DATATYPE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 429, 4,
65
     CEOS_REC_TYP_A}, /* Data type */
66
    {CEOS_REC_BPR, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 0, 0,
67
     CEOS_REC_TYP_A}, /* For Default CEOS, this is done using other vals */
68
    {CEOS_REC_LINES, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 237, 8,
69
     CEOS_REC_TYP_I}, /* How many lines */
70
    {CEOS_REC_TBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 261, 4, CEOS_REC_TYP_I},
71
    {CEOS_REC_BBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 265, 4,
72
     CEOS_REC_TYP_I}, /* Bottom border pixels */
73
    {CEOS_REC_PPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 249, 8,
74
     CEOS_REC_TYP_I}, /* Pixels per line */
75
    {CEOS_REC_LBP, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 245, 4,
76
     CEOS_REC_TYP_I}, /* Left Border Pixels */
77
    {CEOS_REC_RBP, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 257, 4,
78
     CEOS_REC_TYP_I}, /* Right Border Pixels */
79
    {CEOS_REC_BPP, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 225, 4,
80
     CEOS_REC_TYP_I}, /* Bytes Per Pixel */
81
    {CEOS_REC_RPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 273, 2,
82
     CEOS_REC_TYP_I}, /* Records per line */
83
    {CEOS_REC_PPR, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 0, 0,
84
     CEOS_REC_TYP_I}, /* Pixels Per Record -- need to fill record type */
85
    {CEOS_REC_PDBPR, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 281, 8,
86
     CEOS_REC_TYP_I}, /* pixel data bytes per record */
87
    {CEOS_REC_IDS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 277, 4,
88
     CEOS_REC_TYP_I}, /* Prefix data per record */
89
    {CEOS_REC_FDL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 9, 4,
90
     CEOS_REC_TYP_B}, /* Length of Imagry Options Header */
91
    {CEOS_REC_PIXORD, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 0, 0,
92
     CEOS_REC_TYP_I}, /* Must be calculated */
93
    {CEOS_REC_LINORD, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 0, 0,
94
     CEOS_REC_TYP_I}, /* Must be calculated */
95
    {CEOS_REC_PRODTYPE, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 0, 0,
96
     CEOS_REC_TYP_I},
97
98
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC, 9, 4,
99
     CEOS_REC_TYP_B}, /* The processed image record size */
100
101
    /* Some ERS-1 products use an alternate data record subtype2. */
102
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC_ALT, 9, 4,
103
     CEOS_REC_TYP_B}, /* The processed image record size */
104
105
    /* Yet another ERS-1 and ERS-2 alternate data record subtype2. */
106
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC_ALT2, 9, 4,
107
     CEOS_REC_TYP_B}, /* The processed image record size */
108
109
    {CEOS_REC_SUFFIX_SIZE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 289, 4,
110
     CEOS_REC_TYP_I},                /* Suffix data per record */
111
    {0, 0, 0, {0, 0, 0, 0}, 0, 0, 0} /* Last record is Zero */
112
};
113
114
static const CeosRecipeType_t JersRecipe[] = {
115
    {CEOS_REC_NUMCHANS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 233, 4,
116
     CEOS_REC_TYP_I}, /* Number of channels */
117
    {CEOS_REC_INTERLEAVE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 269, 4,
118
     CEOS_REC_TYP_A}, /* Interleaving type */
119
    {CEOS_REC_DATATYPE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 429, 4,
120
     CEOS_REC_TYP_A}, /* Data type */
121
    {CEOS_REC_BPR, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 0, 0,
122
     CEOS_REC_TYP_A}, /* For Default CEOS, this is done using other vals */
123
    {CEOS_REC_LINES, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 237, 8,
124
     CEOS_REC_TYP_I}, /* How many lines */
125
    {CEOS_REC_TBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 261, 4,
126
     CEOS_REC_TYP_I},
127
    {CEOS_REC_BBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 265, 4,
128
     CEOS_REC_TYP_I}, /* Bottom border pixels */
129
    {CEOS_REC_PPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 249, 8,
130
     CEOS_REC_TYP_I}, /* Pixels per line */
131
    {CEOS_REC_LBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 245, 4,
132
     CEOS_REC_TYP_I}, /* Left Border Pixels */
133
    {CEOS_REC_RBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 257, 4,
134
     CEOS_REC_TYP_I}, /* Isn't available for RadarSAT */
135
    {CEOS_REC_BPP, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 225, 4,
136
     CEOS_REC_TYP_I}, /* Bytes Per Pixel */
137
    {CEOS_REC_RPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 273, 2,
138
     CEOS_REC_TYP_I}, /* Records per line */
139
    {CEOS_REC_PPR, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 0, 0,
140
     CEOS_REC_TYP_I}, /* Pixels Per Record -- need to fill record type */
141
    {CEOS_REC_PDBPR, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 281, 8,
142
     CEOS_REC_TYP_I}, /* pixel data bytes per record */
143
    {CEOS_REC_IDS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 277, 4,
144
     CEOS_REC_TYP_I}, /* Prefix data per record */
145
    {CEOS_REC_FDL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 9, 4,
146
     CEOS_REC_TYP_B}, /* Length of Imagry Options Header */
147
    {CEOS_REC_PIXORD, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 0, 0,
148
     CEOS_REC_TYP_I}, /* Must be calculated */
149
    {CEOS_REC_LINORD, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 0, 0,
150
     CEOS_REC_TYP_I}, /* Must be calculated */
151
    {CEOS_REC_PRODTYPE, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 0, 0,
152
     CEOS_REC_TYP_I},
153
154
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC, 9, 4,
155
     CEOS_REC_TYP_B}, /* The processed image record size */
156
157
    /* Alternate data record subtype2. */
158
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC_ALOS2_L1_1, 9,
159
     4, CEOS_REC_TYP_B}, /* The processed image record size */
160
161
    {CEOS_REC_SUFFIX_SIZE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_JERS_OPT, 289, 4,
162
     CEOS_REC_TYP_I},                /* Suffix data per record */
163
    {0, 0, 0, {0, 0, 0, 0}, 0, 0, 0} /* Last record is Zero */
164
};
165
166
static const CeosRecipeType_t ScanSARRecipe[] = {
167
    {CEOS_REC_NUMCHANS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 233, 4,
168
     CEOS_REC_TYP_I}, /* Number of channels */
169
    {CEOS_REC_INTERLEAVE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 269, 4,
170
     CEOS_REC_TYP_A}, /* Interleaving type */
171
    {CEOS_REC_DATATYPE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 429, 4,
172
     CEOS_REC_TYP_A}, /* Data type */
173
    {CEOS_REC_LINES, 1, CEOS_ANY_FILE, DATA_SET_SUMMARY, 325, 8,
174
     CEOS_REC_TYP_I}, /* How many lines */
175
    {CEOS_REC_PPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 249, 8,
176
     CEOS_REC_TYP_I}, /* Pixels per line */
177
    {CEOS_REC_BPP, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 225, 4,
178
     CEOS_REC_TYP_I}, /* Bytes Per Pixel */
179
    {CEOS_REC_RPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 273, 2,
180
     CEOS_REC_TYP_I}, /* Records per line */
181
    {CEOS_REC_IDS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 277, 4,
182
     CEOS_REC_TYP_I}, /* Prefix data per record */
183
    {CEOS_REC_FDL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 9, 4,
184
     CEOS_REC_TYP_B}, /* Length of Imagry Options Header */
185
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC, 9, 4,
186
     CEOS_REC_TYP_B}, /* The processed image record size */
187
    {CEOS_REC_SUFFIX_SIZE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 289, 4,
188
     CEOS_REC_TYP_I},                /* Suffix data per record */
189
    {0, 0, 0, {0, 0, 0, 0}, 0, 0, 0} /* Last record is Zero */
190
};
191
192
static const CeosRecipeType_t SIRCRecipe[] = {
193
    {CEOS_REC_NUMCHANS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 233, 4,
194
     CEOS_REC_TYP_I}, /* Number of channels */
195
    {CEOS_REC_INTERLEAVE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 269, 4,
196
     CEOS_REC_TYP_A}, /* Interleaving type */
197
    {CEOS_REC_DATATYPE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 429, 4,
198
     CEOS_REC_TYP_A}, /* Data type */
199
    {CEOS_REC_LINES, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 237, 8,
200
     CEOS_REC_TYP_I}, /* How many lines */
201
    {CEOS_REC_TBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 261, 4, CEOS_REC_TYP_I},
202
    {CEOS_REC_BBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 265, 4,
203
     CEOS_REC_TYP_I}, /* Bottom border pixels */
204
    {CEOS_REC_PPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 249, 8,
205
     CEOS_REC_TYP_I}, /* Pixels per line */
206
    {CEOS_REC_LBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 245, 4,
207
     CEOS_REC_TYP_I}, /* Left Border Pixels */
208
    {CEOS_REC_RBP, 0, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 257, 4,
209
     CEOS_REC_TYP_I}, /* Right Border Pixels */
210
    {CEOS_REC_BPP, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 225, 4,
211
     CEOS_REC_TYP_I}, /* Bytes Per Pixel */
212
    {CEOS_REC_RPL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 273, 2,
213
     CEOS_REC_TYP_I}, /* Records per line */
214
    {CEOS_REC_IDS, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 277, 4,
215
     CEOS_REC_TYP_I}, /* Prefix data per record */
216
    {CEOS_REC_FDL, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 9, 4,
217
     CEOS_REC_TYP_B}, /* Length of Imagry Options Header */
218
    {CEOS_REC_RECORDSIZE, 1, CEOS_IMAGRY_OPT_FILE, PROC_DATA_REC, 9, 4,
219
     CEOS_REC_TYP_B}, /* The processed image record size */
220
    {CEOS_REC_SUFFIX_SIZE, 1, CEOS_IMAGRY_OPT_FILE, IMAGE_OPT, 289, 4,
221
     CEOS_REC_TYP_I}, /* Suffix data per record */
222
223
    {0, 0, 0, {0, 0, 0, 0}, 0, 0, 0} /* Last record is Zero */
224
};
225
226
#undef PROC_DATA_REC
227
228
static void ExtractInt(CeosRecord_t *record, int type, unsigned int offset,
229
                       unsigned int length, int *value);
230
231
static char *ExtractString(CeosRecord_t *record, unsigned int offset,
232
                           unsigned int length, char *string);
233
234
static int GetCeosStringType(const CeosStringType_t *CeosType,
235
                             const char *string);
236
237
static int SIRCRecipeFCN(CeosSARVolume_t *volume, const void *token);
238
static int PALSARRecipeFCN(CeosSARVolume_t *volume, const void *token);
239
240
Link_t *RecipeFunctions = NULL;
241
242
void RegisterRecipes(void)
243
23
{
244
245
23
    AddRecipe(SIRCRecipeFCN, SIRCRecipe, "SIR-C");
246
23
    AddRecipe(ScanSARRecipeFCN, ScanSARRecipe, "ScanSAR");
247
23
    AddRecipe(CeosDefaultRecipe, RadarSatRecipe, "RadarSat");
248
23
    AddRecipe(CeosDefaultRecipe, JersRecipe, "Jers");
249
23
    AddRecipe(PALSARRecipeFCN, RadarSatRecipe, "PALSAR-ALOS");
250
    /*  AddRecipe( CeosDefaultRecipe, AtlantisRecipe ); */
251
23
}
252
253
void FreeRecipes(void)
254
255
33
{
256
33
    Link_t *l_link;
257
258
148
    for (l_link = RecipeFunctions; l_link != NULL; l_link = l_link->next)
259
115
        HFree(l_link->object);
260
261
33
    DestroyList(RecipeFunctions);
262
33
    RecipeFunctions = NULL;
263
33
}
264
265
void AddRecipe(int (*function)(CeosSARVolume_t *volume, const void *token),
266
               const void *token, const char *name)
267
115
{
268
269
115
    RecipeFunctionData_t *TempData;
270
271
115
    Link_t *Link;
272
273
115
    TempData = HMalloc(sizeof(RecipeFunctionData_t));
274
275
115
    TempData->function = function;
276
115
    TempData->token = token;
277
115
    TempData->name = name;
278
279
115
    Link = ceos2CreateLink(TempData);
280
281
115
    if (RecipeFunctions == NULL)
282
23
    {
283
23
        RecipeFunctions = Link;
284
23
    }
285
92
    else
286
92
    {
287
92
        RecipeFunctions = InsertLink(RecipeFunctions, Link);
288
92
    }
289
115
}
290
291
int CeosDefaultRecipe(CeosSARVolume_t *volume, const void *token)
292
55
{
293
55
    const CeosRecipeType_t *recipe;
294
55
    CeosRecord_t *record;
295
55
    CeosTypeCode_t TypeCode = {0};
296
55
    struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
297
55
    char temp_str[1024];
298
55
    int i /*, temp_int */;
299
300
55
#define DoExtractInt(a)                                                        \
301
350
    ExtractInt(record, recipe[i].Type, recipe[i].Offset, recipe[i].Length, &a)
302
303
55
    if (token == NULL)
304
0
    {
305
0
        return 0;
306
0
    }
307
308
55
    memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
309
310
    /*    temp_imagerecipe = (CeosSARImageDescRecipe_t *) token;
311
        recipe = temp_imagerecipe->Recipe; */
312
313
55
    recipe = token;
314
315
1.18k
    for (i = 0; recipe[i].ImageDescValue != 0; i++)
316
1.13k
    {
317
1.13k
        if (recipe[i].Override)
318
766
        {
319
766
            TypeCode.UCharCode.Subtype1 = recipe[i].TypeCode.Subtype1;
320
766
            TypeCode.UCharCode.Type = recipe[i].TypeCode.Type;
321
766
            TypeCode.UCharCode.Subtype2 = recipe[i].TypeCode.Subtype2;
322
766
            TypeCode.UCharCode.Subtype3 = recipe[i].TypeCode.Subtype3;
323
324
766
            record = FindCeosRecord(volume->RecordList, TypeCode,
325
766
                                    recipe[i].FileId, -1, -1);
326
327
766
            if (record == NULL)
328
352
            {
329
                /* temp_int = 0; */
330
352
            }
331
414
            else
332
414
            {
333
334
414
                switch (recipe[i].ImageDescValue)
335
414
                {
336
32
                    case CEOS_REC_NUMCHANS:
337
32
                        DoExtractInt(ImageDesc->NumChannels);
338
32
                        break;
339
23
                    case CEOS_REC_LINES:
340
23
                        DoExtractInt(ImageDesc->Lines);
341
23
                        break;
342
32
                    case CEOS_REC_BPP:
343
32
                        DoExtractInt(ImageDesc->BytesPerPixel);
344
32
                        break;
345
32
                    case CEOS_REC_RPL:
346
32
                        DoExtractInt(ImageDesc->RecordsPerLine);
347
32
                        break;
348
23
                    case CEOS_REC_PDBPR:
349
23
                        DoExtractInt(ImageDesc->PixelDataBytesPerRecord);
350
23
                        break;
351
32
                    case CEOS_REC_FDL:
352
32
                        DoExtractInt(ImageDesc->FileDescriptorLength);
353
32
                        break;
354
32
                    case CEOS_REC_IDS:
355
32
                        DoExtractInt(ImageDesc->ImageDataStart);
356
                        /*
357
                        ** This is really reading the quantity of prefix data
358
                        ** per data record.  We want the offset from the very
359
                        ** beginning of the record to the data, so we add
360
                        *another
361
                        ** CEOS_HEADER_LENGTH to that.  I think some products incorrectly
362
                        *indicate
363
                        ** 192 (prefix+CEOS_HEADER_LENGTH) instead of 180 so if we see 192
364
                        *assume
365
                        ** the CEOS_HEADER_LENGTH bytes of record start data has already been
366
                        ** added.  Frank Warmerdam.
367
                        */
368
                        // PALSAR-2 ALOS2 Level 1.1 products have ImageDataStart=544
369
                        // cf https://www.eorc.jaxa.jp/ALOS/en/alos-2/pdf/product_format_description/PALSAR-2_xx_Format_CEOS_E_g.pdf, page 87
370
                        // PALSAR-3 ALOS4 Level 1.0/1.1/1.2  products have ImageDataStart=800
371
                        // cf  https://www.eorc.jaxa.jp/ALOS/en/alos-4/pdf/FTR-240031A_ALOS-4_PALSAR-3_StandardProduct_Format_CEOS_En.pdf, page "4.6-47"
372
                        // and this does not need the +CEOS_HEADER_LENGTH
373
32
                        if (ImageDesc->ImageDataStart != 192 &&
374
20
                            ImageDesc->ImageDataStart != 544 &&
375
20
                            ImageDesc->ImageDataStart != 800)
376
20
                        {
377
20
                            CPLDebug("SAR_CEOS",
378
20
                                     "Patching ImageDataStart from %d to %d",
379
20
                                     ImageDesc->ImageDataStart,
380
20
                                     ImageDesc->ImageDataStart +
381
20
                                         CEOS_HEADER_LENGTH);
382
20
                            ImageDesc->ImageDataStart += CEOS_HEADER_LENGTH;
383
20
                        }
384
32
                        break;
385
32
                    case CEOS_REC_SUFFIX_SIZE:
386
32
                        DoExtractInt(ImageDesc->ImageSuffixData);
387
32
                        break;
388
34
                    case CEOS_REC_RECORDSIZE:
389
34
                        DoExtractInt(ImageDesc->BytesPerRecord);
390
34
                        break;
391
32
                    case CEOS_REC_PPL:
392
32
                        DoExtractInt(ImageDesc->PixelsPerLine);
393
32
                        break;
394
0
                    case CEOS_REC_TBP:
395
0
                        DoExtractInt(ImageDesc->TopBorderPixels);
396
0
                        break;
397
0
                    case CEOS_REC_BBP:
398
0
                        DoExtractInt(ImageDesc->BottomBorderPixels);
399
0
                        break;
400
23
                    case CEOS_REC_LBP:
401
23
                        DoExtractInt(ImageDesc->LeftBorderPixels);
402
23
                        break;
403
23
                    case CEOS_REC_RBP:
404
23
                        DoExtractInt(ImageDesc->RightBorderPixels);
405
23
                        break;
406
32
                    case CEOS_REC_INTERLEAVE:
407
32
                        ExtractString(record, recipe[i].Offset,
408
32
                                      recipe[i].Length, temp_str);
409
410
32
                        ImageDesc->ChannelInterleaving =
411
32
                            GetCeosStringType(CeosInterleaveType, temp_str);
412
32
                        break;
413
32
                    case CEOS_REC_DATATYPE:
414
32
                        ExtractString(record, recipe[i].Offset,
415
32
                                      recipe[i].Length, temp_str);
416
417
32
                        ImageDesc->DataType =
418
32
                            GetCeosStringType(CeosDataType, temp_str);
419
32
                        break;
420
414
                }
421
414
            }
422
766
        }
423
1.13k
    }
424
425
    /* Some files (Telaviv) don't record the number of pixel groups per line.
426
     * Try to derive it from the size of a data group, and the number of
427
     * bytes of pixel data if necessary.
428
     */
429
430
55
    if (ImageDesc->PixelsPerLine == 0 &&
431
37
        ImageDesc->PixelDataBytesPerRecord != 0 &&
432
7
        ImageDesc->BytesPerPixel != 0)
433
6
    {
434
6
        ImageDesc->PixelsPerLine =
435
6
            ImageDesc->PixelDataBytesPerRecord / ImageDesc->BytesPerPixel;
436
6
        CPLDebug("SAR_CEOS", "Guessing PixelPerLine to be %d\n",
437
6
                 ImageDesc->PixelsPerLine);
438
6
    }
439
440
    /* Some files don't have the BytesPerRecord stuff, so we calculate it if
441
     * possible */
442
443
55
    if (ImageDesc->BytesPerRecord == 0 && ImageDesc->RecordsPerLine == 1 &&
444
0
        ImageDesc->PixelsPerLine > 0 && ImageDesc->BytesPerPixel > 0)
445
0
    {
446
0
        CeosRecord_t *img_rec;
447
448
0
        ImageDesc->BytesPerRecord =
449
0
            ImageDesc->PixelsPerLine * ImageDesc->BytesPerPixel +
450
0
            ImageDesc->ImageDataStart + ImageDesc->ImageSuffixData;
451
452
0
        TypeCode.UCharCode.Subtype1 = 0xed;
453
0
        TypeCode.UCharCode.Type = 0xed;
454
0
        TypeCode.UCharCode.Subtype2 = 0x12;
455
0
        TypeCode.UCharCode.Subtype3 = 0x12;
456
457
0
        img_rec = FindCeosRecord(volume->RecordList, TypeCode,
458
0
                                 CEOS_IMAGRY_OPT_FILE, -1, -1);
459
0
        if (img_rec == NULL)
460
0
        {
461
0
            CPLDebug("SAR_CEOS",
462
0
                     "Unable to find imagery rec to check record length.");
463
0
            return 0;
464
0
        }
465
466
0
        if (img_rec->Length != ImageDesc->BytesPerRecord)
467
0
        {
468
0
            CPLDebug("SAR_CEOS",
469
0
                     "Guessed record length (%d) did not match\n"
470
0
                     "actual imagery record length (%d), recipe fails.",
471
0
                     ImageDesc->BytesPerRecord, img_rec->Length);
472
0
            return 0;
473
0
        }
474
0
    }
475
476
55
    if (ImageDesc->PixelsPerRecord == 0 && ImageDesc->BytesPerRecord != 0 &&
477
34
        ImageDesc->BytesPerPixel != 0)
478
18
    {
479
18
        ImageDesc->PixelsPerRecord =
480
18
            ((ImageDesc->BytesPerRecord -
481
18
              (ImageDesc->ImageSuffixData + ImageDesc->ImageDataStart)) /
482
18
             ImageDesc->BytesPerPixel);
483
484
18
        if (ImageDesc->PixelsPerRecord > ImageDesc->PixelsPerLine)
485
3
            ImageDesc->PixelsPerRecord = ImageDesc->PixelsPerLine;
486
18
    }
487
488
    /* If we didn't get a data type, try guessing. */
489
55
    if (ImageDesc->DataType == 0 && ImageDesc->BytesPerPixel != 0 &&
490
15
        ImageDesc->NumChannels != 0)
491
15
    {
492
15
        int nDataTypeSize = ImageDesc->BytesPerPixel / ImageDesc->NumChannels;
493
494
15
        if (nDataTypeSize == 1)
495
5
            ImageDesc->DataType = CEOS_TYP_UCHAR;
496
10
        else if (nDataTypeSize == 2)
497
0
            ImageDesc->DataType = CEOS_TYP_USHORT;
498
15
    }
499
500
    /* Sanity checking */
501
502
55
    if (ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
503
17
        ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
504
16
        ImageDesc->FileDescriptorLength == 0 || ImageDesc->DataType == 0 ||
505
16
        ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
506
15
        ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
507
41
    {
508
41
        return 0;
509
41
    }
510
14
    else
511
14
    {
512
513
14
        ImageDesc->ImageDescValid = TRUE;
514
14
        return 1;
515
14
    }
516
55
}
517
518
int ScanSARRecipeFCN(CeosSARVolume_t *volume, const void *token)
519
9
{
520
9
    struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
521
522
9
    memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
523
524
9
    if (CeosDefaultRecipe(volume, token))
525
0
    {
526
0
        ImageDesc->Lines *= 2;
527
0
        return 1;
528
0
    }
529
530
9
    return 0;
531
9
}
532
533
static int SIRCRecipeFCN(CeosSARVolume_t *volume, const void *token)
534
9
{
535
9
    struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
536
9
    CeosTypeCode_t TypeCode = {0};
537
9
    CeosRecord_t *record;
538
9
    char szSARDataFormat[29];
539
540
9
    memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
541
542
    /* -------------------------------------------------------------------- */
543
    /*      First, we need to check if the "SAR Data Format Type            */
544
    /*      identifier" is set to "COMPRESSED CROSS-PRODUCTS" which is      */
545
    /*      pretty idiosyncratic to SIRC products.  It might also appear    */
546
    /*      for some other similarly encoded Polarimetric data I suppose.    */
547
    /* -------------------------------------------------------------------- */
548
    /* IMAGE_OPT */
549
9
    TypeCode.UCharCode.Subtype1 = 63;
550
9
    TypeCode.UCharCode.Type = 192;
551
9
    TypeCode.UCharCode.Subtype2 = 18;
552
9
    TypeCode.UCharCode.Subtype3 = 18;
553
554
9
    record = FindCeosRecord(volume->RecordList, TypeCode, CEOS_IMAGRY_OPT_FILE,
555
9
                            -1, -1);
556
9
    if (record == NULL)
557
0
        return 0;
558
559
9
    ExtractString(record, 401, 28, szSARDataFormat);
560
9
    if (!STARTS_WITH_CI(szSARDataFormat, "COMPRESSED CROSS-PRODUCTS"))
561
9
        return 0;
562
563
    /* -------------------------------------------------------------------- */
564
    /*      Apply normal handling...                                        */
565
    /* -------------------------------------------------------------------- */
566
0
    CeosDefaultRecipe(volume, token);
567
568
    /* -------------------------------------------------------------------- */
569
    /*      Make sure this looks like the SIRC product we are expecting.    */
570
    /* -------------------------------------------------------------------- */
571
0
    if (ImageDesc->BytesPerPixel != 10)
572
0
        return 0;
573
574
    /* -------------------------------------------------------------------- */
575
    /*      Then fix up a few values.                                       */
576
    /* -------------------------------------------------------------------- */
577
    /* It seems the bytes of pixel data per record is just wrong.  Fix. */
578
0
    ImageDesc->PixelDataBytesPerRecord =
579
0
        ImageDesc->BytesPerPixel * ImageDesc->PixelsPerLine;
580
581
0
    ImageDesc->DataType = CEOS_TYP_CCP_COMPLEX_FLOAT;
582
583
    /* -------------------------------------------------------------------- */
584
    /*      Sanity checking                                                 */
585
    /* -------------------------------------------------------------------- */
586
0
    if (ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
587
0
        ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
588
0
        ImageDesc->FileDescriptorLength == 0 || ImageDesc->NumChannels == 0 ||
589
0
        ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
590
0
    {
591
0
        return 0;
592
0
    }
593
0
    else
594
0
    {
595
0
        ImageDesc->ImageDescValid = TRUE;
596
0
        return 1;
597
0
    }
598
0
}
599
600
static int PALSARRecipeFCN(CeosSARVolume_t *volume, const void *token)
601
23
{
602
23
    struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
603
23
    CeosTypeCode_t TypeCode = {0};
604
23
    CeosRecord_t *record;
605
23
    char szSARDataFormat[29], szProduct[32];
606
607
23
    memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
608
609
    /* -------------------------------------------------------------------- */
610
    /*      First, we need to check if the "SAR Data Format Type            */
611
    /*      identifier" is set to "COMPRESSED CROSS-PRODUCTS" which is      */
612
    /*      pretty idiosyncratic to SIRC products.  It might also appear    */
613
    /*      for some other similarly encoded Polarimetric data I suppose.    */
614
    /* -------------------------------------------------------------------- */
615
    /* IMAGE_OPT */
616
23
    TypeCode.UCharCode.Subtype1 = 63;
617
23
    TypeCode.UCharCode.Type = 192;
618
23
    TypeCode.UCharCode.Subtype2 = 18;
619
23
    TypeCode.UCharCode.Subtype3 = 18;
620
621
23
    record = FindCeosRecord(volume->RecordList, TypeCode, CEOS_IMAGRY_OPT_FILE,
622
23
                            -1, -1);
623
23
    if (record == NULL)
624
0
        return 0;
625
626
23
    ExtractString(record, 401, 28, szSARDataFormat);
627
23
    if (!STARTS_WITH_CI(szSARDataFormat, "INTEGER*18                 "))
628
23
        return 0;
629
630
0
    ExtractString(record, 49, 16, szProduct);
631
0
    if (!STARTS_WITH_CI(szProduct, "ALOS-"))
632
0
        return 0;
633
634
    /* -------------------------------------------------------------------- */
635
    /*      Apply normal handling...                                        */
636
    /* -------------------------------------------------------------------- */
637
0
    CeosDefaultRecipe(volume, token);
638
639
    /* -------------------------------------------------------------------- */
640
    /*      Make sure this looks like the SIRC product we are expecting.    */
641
    /* -------------------------------------------------------------------- */
642
0
    if (ImageDesc->BytesPerPixel != 18)
643
0
        return 0;
644
645
    /* -------------------------------------------------------------------- */
646
    /*      Then fix up a few values.                                       */
647
    /* -------------------------------------------------------------------- */
648
0
    ImageDesc->DataType = CEOS_TYP_PALSAR_COMPLEX_SHORT;
649
0
    ImageDesc->NumChannels = 6;
650
651
    /* -------------------------------------------------------------------- */
652
    /*      Sanity checking                                                 */
653
    /* -------------------------------------------------------------------- */
654
0
    if (ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
655
0
        ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
656
0
        ImageDesc->FileDescriptorLength == 0 ||
657
0
        ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
658
0
    {
659
0
        return 0;
660
0
    }
661
0
    else
662
0
    {
663
0
        ImageDesc->ImageDescValid = TRUE;
664
0
        return 1;
665
0
    }
666
0
}
667
668
void GetCeosSARImageDesc(CeosSARVolume_t *volume)
669
23
{
670
23
    Link_t *l_link;
671
23
    RecipeFunctionData_t *rec_data;
672
23
    int (*function)(CeosSARVolume_t *volume, const void *token);
673
674
23
    if (RecipeFunctions == NULL)
675
23
    {
676
23
        RegisterRecipes();
677
23
    }
678
679
23
    if (RecipeFunctions == NULL)
680
0
    {
681
0
        return;
682
0
    }
683
684
96
    for (l_link = RecipeFunctions; l_link != NULL; l_link = l_link->next)
685
87
    {
686
87
        if (l_link->object)
687
87
        {
688
87
            rec_data = l_link->object;
689
87
            function = rec_data->function;
690
87
            if ((*function)(volume, rec_data->token))
691
14
            {
692
14
                CPLDebug("CEOS", "Using recipe '%s'.", rec_data->name);
693
14
                return;
694
14
            }
695
87
        }
696
87
    }
697
698
9
    return;
699
23
}
700
701
static void ExtractInt(CeosRecord_t *record, int type, unsigned int offset,
702
                       unsigned int length, int *value)
703
350
{
704
350
    void *buffer;
705
350
    char format[32];
706
707
350
    buffer = HMalloc(length + 1);
708
709
350
    switch (type)
710
350
    {
711
0
        case CEOS_REC_TYP_A:
712
0
            snprintf(format, sizeof(format), "A%u", length);
713
0
            GetCeosField(record, offset, format, buffer);
714
0
            *value = atoi(buffer);
715
0
            break;
716
66
        case CEOS_REC_TYP_B:
717
66
            snprintf(format, sizeof(format), "B%u", length);
718
#ifdef notdef
719
            GetCeosField(record, offset, format, buffer);
720
            if (length <= 4)
721
                CeosToNative(value, buffer, length, length);
722
            else
723
                *value = 0;
724
#else
725
66
            GetCeosField(record, offset, format, value);
726
66
#endif
727
66
            break;
728
284
        case CEOS_REC_TYP_I:
729
284
            snprintf(format, sizeof(format), "I%u", length);
730
284
            GetCeosField(record, offset, format, value);
731
284
            break;
732
350
    }
733
734
350
    HFree(buffer);
735
350
}
736
737
static char *ExtractString(CeosRecord_t *record, unsigned int offset,
738
                           unsigned int length, char *string)
739
96
{
740
96
    char format[12];
741
742
96
    if (string == NULL)
743
0
    {
744
0
        string = HMalloc(length + 1);
745
0
    }
746
747
96
    snprintf(format, sizeof(format), "A%u", length);
748
749
96
    GetCeosField(record, offset, format, string);
750
751
96
    return string;
752
96
}
753
754
static int GetCeosStringType(const CeosStringType_t *CeosStringType,
755
                             const char *string)
756
64
{
757
64
    int i;
758
759
294
    for (i = 0; CeosStringType[i].String != NULL; i++)
760
263
    {
761
263
        if (strncmp(CeosStringType[i].String, string,
762
263
                    strlen(CeosStringType[i].String)) == 0)
763
33
        {
764
33
            return CeosStringType[i].Type;
765
33
        }
766
263
    }
767
768
31
    return 0;
769
64
}