Line data Source code
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 5 : void RegisterRecipes(void)
243 : {
244 :
245 5 : AddRecipe(SIRCRecipeFCN, SIRCRecipe, "SIR-C");
246 5 : AddRecipe(ScanSARRecipeFCN, ScanSARRecipe, "ScanSAR");
247 5 : AddRecipe(CeosDefaultRecipe, RadarSatRecipe, "RadarSat");
248 5 : AddRecipe(CeosDefaultRecipe, JersRecipe, "Jers");
249 5 : AddRecipe(PALSARRecipeFCN, RadarSatRecipe, "PALSAR-ALOS");
250 : /* AddRecipe( CeosDefaultRecipe, AtlantisRecipe ); */
251 5 : }
252 :
253 7 : void FreeRecipes(void)
254 :
255 : {
256 : Link_t *l_link;
257 :
258 32 : for (l_link = RecipeFunctions; l_link != NULL; l_link = l_link->next)
259 25 : HFree(l_link->object);
260 :
261 7 : DestroyList(RecipeFunctions);
262 7 : RecipeFunctions = NULL;
263 7 : }
264 :
265 25 : void AddRecipe(int (*function)(CeosSARVolume_t *volume, const void *token),
266 : const void *token, const char *name)
267 : {
268 :
269 : RecipeFunctionData_t *TempData;
270 :
271 : Link_t *Link;
272 :
273 25 : TempData = HMalloc(sizeof(RecipeFunctionData_t));
274 :
275 25 : TempData->function = function;
276 25 : TempData->token = token;
277 25 : TempData->name = name;
278 :
279 25 : Link = ceos2CreateLink(TempData);
280 :
281 25 : if (RecipeFunctions == NULL)
282 : {
283 5 : RecipeFunctions = Link;
284 : }
285 : else
286 : {
287 20 : RecipeFunctions = InsertLink(RecipeFunctions, Link);
288 : }
289 25 : }
290 :
291 11 : int CeosDefaultRecipe(CeosSARVolume_t *volume, const void *token)
292 : {
293 : const CeosRecipeType_t *recipe;
294 : CeosRecord_t *record;
295 11 : CeosTypeCode_t TypeCode = {0};
296 11 : struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
297 : char temp_str[1024];
298 : int i /*, temp_int */;
299 :
300 : #define DoExtractInt(a) \
301 : ExtractInt(record, recipe[i].Type, recipe[i].Offset, recipe[i].Length, &a)
302 :
303 11 : if (token == NULL)
304 : {
305 0 : return 0;
306 : }
307 :
308 11 : memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
309 :
310 : /* temp_imagerecipe = (CeosSARImageDescRecipe_t *) token;
311 : recipe = temp_imagerecipe->Recipe; */
312 :
313 11 : recipe = token;
314 :
315 257 : for (i = 0; recipe[i].ImageDescValue != 0; i++)
316 : {
317 246 : if (recipe[i].Override)
318 : {
319 155 : TypeCode.UCharCode.Subtype1 = recipe[i].TypeCode.Subtype1;
320 155 : TypeCode.UCharCode.Type = recipe[i].TypeCode.Type;
321 155 : TypeCode.UCharCode.Subtype2 = recipe[i].TypeCode.Subtype2;
322 155 : TypeCode.UCharCode.Subtype3 = recipe[i].TypeCode.Subtype3;
323 :
324 155 : record = FindCeosRecord(volume->RecordList, TypeCode,
325 155 : recipe[i].FileId, -1, -1);
326 :
327 155 : if (record == NULL)
328 : {
329 : /* temp_int = 0; */
330 : }
331 : else
332 : {
333 :
334 96 : switch (recipe[i].ImageDescValue)
335 : {
336 7 : case CEOS_REC_NUMCHANS:
337 7 : DoExtractInt(ImageDesc->NumChannels);
338 7 : break;
339 7 : case CEOS_REC_LINES:
340 7 : DoExtractInt(ImageDesc->Lines);
341 7 : break;
342 7 : case CEOS_REC_BPP:
343 7 : DoExtractInt(ImageDesc->BytesPerPixel);
344 7 : break;
345 7 : case CEOS_REC_RPL:
346 7 : DoExtractInt(ImageDesc->RecordsPerLine);
347 7 : break;
348 7 : case CEOS_REC_PDBPR:
349 7 : DoExtractInt(ImageDesc->PixelDataBytesPerRecord);
350 7 : break;
351 7 : case CEOS_REC_FDL:
352 7 : DoExtractInt(ImageDesc->FileDescriptorLength);
353 7 : break;
354 7 : case CEOS_REC_IDS:
355 7 : 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 7 : if (ImageDesc->ImageDataStart != 192 &&
374 4 : ImageDesc->ImageDataStart != 544 &&
375 3 : ImageDesc->ImageDataStart != 800)
376 : {
377 2 : CPLDebug("SAR_CEOS",
378 : "Patching ImageDataStart from %d to %d",
379 : ImageDesc->ImageDataStart,
380 2 : ImageDesc->ImageDataStart +
381 : CEOS_HEADER_LENGTH);
382 2 : ImageDesc->ImageDataStart += CEOS_HEADER_LENGTH;
383 : }
384 7 : break;
385 7 : case CEOS_REC_SUFFIX_SIZE:
386 7 : DoExtractInt(ImageDesc->ImageSuffixData);
387 7 : break;
388 11 : case CEOS_REC_RECORDSIZE:
389 11 : DoExtractInt(ImageDesc->BytesPerRecord);
390 11 : break;
391 7 : case CEOS_REC_PPL:
392 7 : DoExtractInt(ImageDesc->PixelsPerLine);
393 7 : 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 4 : case CEOS_REC_LBP:
401 4 : DoExtractInt(ImageDesc->LeftBorderPixels);
402 4 : break;
403 4 : case CEOS_REC_RBP:
404 4 : DoExtractInt(ImageDesc->RightBorderPixels);
405 4 : break;
406 7 : case CEOS_REC_INTERLEAVE:
407 7 : ExtractString(record, recipe[i].Offset,
408 7 : recipe[i].Length, temp_str);
409 :
410 7 : ImageDesc->ChannelInterleaving =
411 7 : GetCeosStringType(CeosInterleaveType, temp_str);
412 7 : break;
413 7 : case CEOS_REC_DATATYPE:
414 7 : ExtractString(record, recipe[i].Offset,
415 7 : recipe[i].Length, temp_str);
416 :
417 7 : ImageDesc->DataType =
418 7 : GetCeosStringType(CeosDataType, temp_str);
419 7 : break;
420 : }
421 246 : }
422 : }
423 : }
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 11 : if (ImageDesc->PixelsPerLine == 0 &&
431 4 : ImageDesc->PixelDataBytesPerRecord != 0 &&
432 0 : ImageDesc->BytesPerPixel != 0)
433 : {
434 0 : ImageDesc->PixelsPerLine =
435 0 : ImageDesc->PixelDataBytesPerRecord / ImageDesc->BytesPerPixel;
436 0 : CPLDebug("SAR_CEOS", "Guessing PixelPerLine to be %d\n",
437 : ImageDesc->PixelsPerLine);
438 : }
439 :
440 : /* Some files don't have the BytesPerRecord stuff, so we calculate it if
441 : * possible */
442 :
443 11 : if (ImageDesc->BytesPerRecord == 0 && ImageDesc->RecordsPerLine == 1 &&
444 0 : ImageDesc->PixelsPerLine > 0 && ImageDesc->BytesPerPixel > 0)
445 : {
446 : 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 : CEOS_IMAGRY_OPT_FILE, -1, -1);
459 0 : if (img_rec == NULL)
460 : {
461 0 : CPLDebug("SAR_CEOS",
462 : "Unable to find imagery rec to check record length.");
463 0 : return 0;
464 : }
465 :
466 0 : if (img_rec->Length != ImageDesc->BytesPerRecord)
467 : {
468 0 : CPLDebug("SAR_CEOS",
469 : "Guessed record length (%d) did not match\n"
470 : "actual imagery record length (%d), recipe fails.",
471 : ImageDesc->BytesPerRecord, img_rec->Length);
472 0 : return 0;
473 : }
474 : }
475 :
476 11 : if (ImageDesc->PixelsPerRecord == 0 && ImageDesc->BytesPerRecord != 0 &&
477 11 : ImageDesc->BytesPerPixel != 0)
478 : {
479 7 : ImageDesc->PixelsPerRecord =
480 7 : ((ImageDesc->BytesPerRecord -
481 7 : (ImageDesc->ImageSuffixData + ImageDesc->ImageDataStart)) /
482 7 : ImageDesc->BytesPerPixel);
483 :
484 7 : if (ImageDesc->PixelsPerRecord > ImageDesc->PixelsPerLine)
485 0 : ImageDesc->PixelsPerRecord = ImageDesc->PixelsPerLine;
486 : }
487 :
488 : /* If we didn't get a data type, try guessing. */
489 11 : if (ImageDesc->DataType == 0 && ImageDesc->BytesPerPixel != 0 &&
490 0 : ImageDesc->NumChannels != 0)
491 : {
492 0 : int nDataTypeSize = ImageDesc->BytesPerPixel / ImageDesc->NumChannels;
493 :
494 0 : if (nDataTypeSize == 1)
495 0 : ImageDesc->DataType = CEOS_TYP_UCHAR;
496 0 : else if (nDataTypeSize == 2)
497 0 : ImageDesc->DataType = CEOS_TYP_USHORT;
498 : }
499 :
500 : /* Sanity checking */
501 :
502 11 : if (ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
503 7 : ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
504 7 : ImageDesc->FileDescriptorLength == 0 || ImageDesc->DataType == 0 ||
505 7 : ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
506 7 : ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
507 : {
508 4 : return 0;
509 : }
510 : else
511 : {
512 :
513 7 : ImageDesc->ImageDescValid = TRUE;
514 7 : return 1;
515 : }
516 : }
517 :
518 0 : int ScanSARRecipeFCN(CeosSARVolume_t *volume, const void *token)
519 : {
520 0 : struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
521 :
522 0 : memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
523 :
524 0 : if (CeosDefaultRecipe(volume, token))
525 : {
526 0 : ImageDesc->Lines *= 2;
527 0 : return 1;
528 : }
529 :
530 0 : return 0;
531 : }
532 :
533 0 : static int SIRCRecipeFCN(CeosSARVolume_t *volume, const void *token)
534 : {
535 0 : struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
536 0 : CeosTypeCode_t TypeCode = {0};
537 : CeosRecord_t *record;
538 : char szSARDataFormat[29];
539 :
540 0 : 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 0 : TypeCode.UCharCode.Subtype1 = 63;
550 0 : TypeCode.UCharCode.Type = 192;
551 0 : TypeCode.UCharCode.Subtype2 = 18;
552 0 : TypeCode.UCharCode.Subtype3 = 18;
553 :
554 0 : record = FindCeosRecord(volume->RecordList, TypeCode, CEOS_IMAGRY_OPT_FILE,
555 : -1, -1);
556 0 : if (record == NULL)
557 0 : return 0;
558 :
559 0 : ExtractString(record, 401, 28, szSARDataFormat);
560 0 : if (!STARTS_WITH_CI(szSARDataFormat, "COMPRESSED CROSS-PRODUCTS"))
561 0 : 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->DataType == 0 ||
589 0 : ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
590 0 : ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
591 : {
592 0 : return 0;
593 : }
594 : else
595 : {
596 0 : ImageDesc->ImageDescValid = TRUE;
597 0 : return 1;
598 : }
599 : }
600 :
601 7 : static int PALSARRecipeFCN(CeosSARVolume_t *volume, const void *token)
602 : {
603 7 : struct CeosSARImageDesc *ImageDesc = &(volume->ImageDesc);
604 7 : CeosTypeCode_t TypeCode = {0};
605 : CeosRecord_t *record;
606 : char szSARDataFormat[29], szProduct[32];
607 :
608 7 : memset(ImageDesc, 0, sizeof(struct CeosSARImageDesc));
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* First, we need to check if the "SAR Data Format Type */
612 : /* identifier" is set to "COMPRESSED CROSS-PRODUCTS" which is */
613 : /* pretty idiosyncratic to SIRC products. It might also appear */
614 : /* for some other similarly encoded Polarimetric data I suppose. */
615 : /* -------------------------------------------------------------------- */
616 : /* IMAGE_OPT */
617 7 : TypeCode.UCharCode.Subtype1 = 63;
618 7 : TypeCode.UCharCode.Type = 192;
619 7 : TypeCode.UCharCode.Subtype2 = 18;
620 7 : TypeCode.UCharCode.Subtype3 = 18;
621 :
622 7 : record = FindCeosRecord(volume->RecordList, TypeCode, CEOS_IMAGRY_OPT_FILE,
623 : -1, -1);
624 7 : if (record == NULL)
625 3 : return 0;
626 :
627 4 : ExtractString(record, 401, 28, szSARDataFormat);
628 4 : if (!STARTS_WITH_CI(szSARDataFormat, "INTEGER*18 "))
629 4 : return 0;
630 :
631 0 : ExtractString(record, 49, 16, szProduct);
632 0 : if (!STARTS_WITH_CI(szProduct, "ALOS-"))
633 0 : return 0;
634 :
635 : /* -------------------------------------------------------------------- */
636 : /* Apply normal handling... */
637 : /* -------------------------------------------------------------------- */
638 0 : CeosDefaultRecipe(volume, token);
639 :
640 : /* -------------------------------------------------------------------- */
641 : /* Make sure this looks like the SIRC product we are expecting. */
642 : /* -------------------------------------------------------------------- */
643 0 : if (ImageDesc->BytesPerPixel != 18)
644 0 : return 0;
645 :
646 : /* -------------------------------------------------------------------- */
647 : /* Then fix up a few values. */
648 : /* -------------------------------------------------------------------- */
649 0 : ImageDesc->DataType = CEOS_TYP_PALSAR_COMPLEX_SHORT;
650 0 : ImageDesc->NumChannels = 6;
651 :
652 : /* -------------------------------------------------------------------- */
653 : /* Sanity checking */
654 : /* -------------------------------------------------------------------- */
655 0 : if (ImageDesc->PixelsPerLine == 0 || ImageDesc->Lines == 0 ||
656 0 : ImageDesc->RecordsPerLine == 0 || ImageDesc->ImageDataStart == 0 ||
657 0 : ImageDesc->FileDescriptorLength == 0 || ImageDesc->DataType == 0 ||
658 0 : ImageDesc->NumChannels == 0 || ImageDesc->BytesPerPixel == 0 ||
659 0 : ImageDesc->ChannelInterleaving == 0 || ImageDesc->BytesPerRecord == 0)
660 : {
661 0 : return 0;
662 : }
663 : else
664 : {
665 0 : ImageDesc->ImageDescValid = TRUE;
666 0 : return 1;
667 : }
668 : }
669 :
670 7 : void GetCeosSARImageDesc(CeosSARVolume_t *volume)
671 : {
672 : Link_t *l_link;
673 : RecipeFunctionData_t *rec_data;
674 : int (*function)(CeosSARVolume_t *volume, const void *token);
675 :
676 7 : if (RecipeFunctions == NULL)
677 : {
678 5 : RegisterRecipes();
679 : }
680 :
681 7 : if (RecipeFunctions == NULL)
682 : {
683 0 : return;
684 : }
685 :
686 18 : for (l_link = RecipeFunctions; l_link != NULL; l_link = l_link->next)
687 : {
688 18 : if (l_link->object)
689 : {
690 18 : rec_data = l_link->object;
691 18 : function = rec_data->function;
692 18 : if ((*function)(volume, rec_data->token))
693 : {
694 7 : CPLDebug("CEOS", "Using recipe '%s'.", rec_data->name);
695 7 : return;
696 : }
697 : }
698 : }
699 :
700 0 : return;
701 : }
702 :
703 82 : static void ExtractInt(CeosRecord_t *record, int type, unsigned int offset,
704 : unsigned int length, int *value)
705 : {
706 : void *buffer;
707 : char format[32];
708 :
709 82 : buffer = HMalloc(length + 1);
710 :
711 82 : switch (type)
712 : {
713 0 : case CEOS_REC_TYP_A:
714 0 : snprintf(format, sizeof(format), "A%u", length);
715 0 : GetCeosField(record, offset, format, buffer);
716 0 : *value = atoi(buffer);
717 0 : break;
718 18 : case CEOS_REC_TYP_B:
719 18 : snprintf(format, sizeof(format), "B%u", length);
720 : #ifdef notdef
721 : GetCeosField(record, offset, format, buffer);
722 : if (length <= 4)
723 : CeosToNative(value, buffer, length, length);
724 : else
725 : *value = 0;
726 : #else
727 18 : GetCeosField(record, offset, format, value);
728 : #endif
729 18 : break;
730 64 : case CEOS_REC_TYP_I:
731 64 : snprintf(format, sizeof(format), "I%u", length);
732 64 : GetCeosField(record, offset, format, value);
733 64 : break;
734 : }
735 :
736 82 : HFree(buffer);
737 82 : }
738 :
739 18 : static char *ExtractString(CeosRecord_t *record, unsigned int offset,
740 : unsigned int length, char *string)
741 : {
742 : char format[12];
743 :
744 18 : if (string == NULL)
745 : {
746 0 : string = HMalloc(length + 1);
747 : }
748 :
749 18 : snprintf(format, sizeof(format), "A%u", length);
750 :
751 18 : GetCeosField(record, offset, format, string);
752 :
753 18 : return string;
754 : }
755 :
756 14 : static int GetCeosStringType(const CeosStringType_t *CeosStringType,
757 : const char *string)
758 : {
759 : int i;
760 :
761 33 : for (i = 0; CeosStringType[i].String != NULL; i++)
762 : {
763 33 : if (strncmp(CeosStringType[i].String, string,
764 33 : strlen(CeosStringType[i].String)) == 0)
765 : {
766 14 : return CeosStringType[i].Type;
767 : }
768 : }
769 :
770 0 : return 0;
771 : }
|