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