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