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