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