1 /*
2 / gaiagraphics_grids.c
3 /
4 / GRIDS auxiliary helpers
5 /
6 / version 1.0, 2010 July 20
7 /
8 / Author: Sandro Furieri a.furieri@lqt.it
9 /
10 / Copyright (C) 2010  Alessandro Furieri
11 /
12 /    This program is free software: you can redistribute it and/or modify
13 /    it under the terms of the GNU Lesser General Public License as published by
14 /    the Free Software Foundation, either version 3 of the License, or
15 /    (at your option) any later version.
16 /
17 /    This program is distributed in the hope that it will be useful,
18 /    but WITHOUT ANY WARRANTY; without even the implied warranty of
19 /    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 /    GNU Lesser General Public License for more details.
21 /
22 /    You should have received a copy of the GNU Lesser General Public License
23 /    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 /
25 */
26 
27 #include <stdio.h>
28 #include <math.h>
29 #include <float.h>
30 #include <limits.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 
35 #include "gaiagraphics.h"
36 #include "gaiagraphics_internals.h"
37 
38 #define GRID_HGT_3	1
39 #define GRID_HGT_1	2
40 #define GRID_BIN_HDR	3
41 #define GRID_FLT_HDR	4
42 #define GRID_DEM_HDR	5
43 #define GRID_ASCII	6
44 
45 struct grid_codec_data
46 {
47 /* a struct used by GRID codec */
48     int grid_type;
49     int is_writer;
50     int little_endian;
51     void *grid_buffer;
52     long *row_offsets;
53 };
54 
55 GGRAPH_PRIVATE int
gg_image_strip_prepare_from_hgt(FILE * in,int lon,int lat,gGraphStripImagePtr * image_handle)56 gg_image_strip_prepare_from_hgt (FILE * in, int lon, int lat,
57 				 gGraphStripImagePtr * image_handle)
58 {
59 /* preparing to decode an HGT-GRID [by strips] */
60     gGraphStripImagePtr img = NULL;
61     struct grid_codec_data *grid_codec = NULL;
62     long file_length;
63     int type;
64     int width;
65     int height;
66     double pixel_size;
67     double half_pixel;
68     int buf_size;
69     void *grid_buffer = NULL;
70     int ret = GGRAPH_HGT_CODEC_ERROR;
71     *image_handle = NULL;
72 
73 /* retrieving the HGT dimensions */
74     if (fseek (in, 0, SEEK_END) != 0)
75 	return GGRAPH_HGT_CODEC_ERROR;
76     file_length = ftell (in);
77     if (file_length == (1201 * 1201 * sizeof (short)))
78       {
79 	  type = GRID_HGT_3;
80 	  width = 1201;
81 	  height = 1201;
82 	  pixel_size = 1.0 / 1200.0;
83       }
84     else if (file_length == (3601 * 3601 * sizeof (short)))
85       {
86 	  type = GRID_HGT_1;
87 	  width = 3601;
88 	  height = 3601;
89 	  pixel_size = 1.0 / 3600.0;
90       }
91     else
92 	return GGRAPH_HGT_CODEC_ERROR;
93 
94     img =
95 	gg_strip_image_create (in, GGRAPH_IMAGE_HGT, GG_PIXEL_GRID, width,
96 			       height, 16, 1, GGRAPH_SAMPLE_INT, "WGS 84",
97 			       "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
98     if (!img)
99       {
100 	  ret = GGRAPH_INSUFFICIENT_MEMORY;
101 	  goto error;
102       }
103 /* setting up georeferencing infos */
104     half_pixel = pixel_size / 2.0;
105     img->is_georeferenced = 1;
106     img->srid = 4326;
107     img->upper_left_x = (double) lon - half_pixel;
108     img->upper_left_y = (double) lat + 1.0 + half_pixel;
109     img->pixel_x_size = pixel_size;
110     img->pixel_y_size = pixel_size;
111     img->no_data_value = SHRT_MIN;
112 
113 /* setting up the GRID codec struct */
114     grid_codec = malloc (sizeof (struct grid_codec_data));
115     if (!grid_codec)
116 	goto error;
117     grid_codec->grid_type = type;
118     grid_codec->is_writer = 0;
119     grid_codec->grid_buffer = NULL;
120     grid_codec->row_offsets = NULL;
121     img->codec_data = grid_codec;
122 
123 /* allocating the GRID read buffer */
124     buf_size = sizeof (short) * width;
125     grid_buffer = malloc (buf_size);
126     if (!grid_buffer)
127 	goto error;
128     grid_codec->grid_buffer = grid_buffer;
129 
130     *image_handle = img;
131     return GGRAPH_OK;
132 
133   error:
134     if (img)
135 	gGraphDestroyImage (img);
136     return ret;
137 }
138 
139 GGRAPH_PRIVATE void
gg_grid_codec_destroy(void * p)140 gg_grid_codec_destroy (void *p)
141 {
142 /* destroyng the GRID codec data */
143     struct grid_codec_data *codec = (struct grid_codec_data *) p;
144     if (!codec)
145 	return;
146     if (codec->grid_buffer)
147 	free (codec->grid_buffer);
148     if (codec->row_offsets)
149 	free (codec->row_offsets);
150     free (codec);
151 }
152 
153 static int
read_from_hgt(FILE * in,gGraphStripImagePtr img,void * scanline)154 read_from_hgt (FILE * in, gGraphStripImagePtr img, void *scanline)
155 {
156 /* decoding an HGT-GRID [by strip] */
157     int width = img->width;
158     int height = img->height;
159     size_t scan_size = width * 2;
160     int row;
161     int incr = 0;
162     int x;
163     int endian_arch = gg_endian_arch ();
164     off_t pos = img->next_row * scan_size;
165     unsigned char *p_in;
166     short *p_out;
167     short cell_value;
168 
169 /* positioning on the start scanline */
170     if (fseek (in, pos, SEEK_SET) != 0)
171 	return GGRAPH_HGT_CODEC_ERROR;
172     for (row = 0; row < img->rows_per_block; row++)
173       {
174 	  /* reading the required number of scanlines */
175 	  if ((row + img->next_row) >= height)
176 	      break;
177 	  if (fread (scanline, 1, scan_size, in) != scan_size)
178 	      return GGRAPH_HGT_CODEC_ERROR;
179 	  p_in = scanline;
180 	  p_out = (short *) (img->pixels);
181 	  p_out += (row * width);
182 	  for (x = 0; x < width; x++)
183 	    {
184 		cell_value = gg_import_int16 (p_in, 0, endian_arch);
185 		*p_out++ = cell_value;
186 		p_in += sizeof (short);
187 	    }
188 	  incr++;
189       }
190     img->next_row += incr;
191     img->current_available_rows = incr;
192     return GGRAPH_OK;
193 }
194 
195 GGRAPH_PRIVATE int
gg_image_strip_read_from_hgt(gGraphStripImagePtr img,int * progress)196 gg_image_strip_read_from_hgt (gGraphStripImagePtr img, int *progress)
197 {
198 /* decoding an HGT-GRID [by strip] */
199     struct grid_codec_data *grid_codec =
200 	(struct grid_codec_data *) (img->codec_data);
201     FILE *in = img->file_handle;
202 
203     if (grid_codec->grid_type == GRID_HGT_1
204 	|| grid_codec->grid_type == GRID_HGT_3)
205       {
206 	  int ret = read_from_hgt (in, img, grid_codec->grid_buffer);
207 	  if (ret == GGRAPH_OK && progress != NULL)
208 	      *progress =
209 		  (int) (((double) (img->next_row + 1) * 100.0) /
210 			 (double) (img->height));
211 	  return ret;
212       }
213     return GGRAPH_ERROR;
214 }
215 
216 GGRAPH_DECLARE int
gGraphCheckHgtPath(const char * path,int * lat,int * lon)217 gGraphCheckHgtPath (const char *path, int *lat, int *lon)
218 {
219 /* checking for HGT format - retrieving coord from path */
220     char file_name[1024];
221     char coord_lat[8];
222     char coord_lon[8];
223     int lat_sign = 1;
224     int lon_sign = 1;
225     int i;
226     int start = 0;
227 
228     for (i = strlen (path) - 1; i >= 0; i--)
229       {
230 	  /* attempting to extract the file name */
231 	  if (path[i] == '/' || path[i] == '\\')
232 	    {
233 		start = i + 1;
234 		break;
235 	    }
236       }
237     strcpy (file_name, path + start);
238 
239     if (strlen (file_name) != 11)
240 	return GGRAPH_ERROR;
241     if (file_name[0] == 'N')
242 	;
243     else if (file_name[0] == 'S')
244 	lat_sign = -1;
245     else
246 	return GGRAPH_ERROR;
247     if (file_name[1] >= '0' && file_name[1] <= '9')
248 	coord_lat[0] = file_name[1];
249     else
250 	return GGRAPH_ERROR;
251     if (file_name[2] >= '0' && file_name[2] <= '9')
252       {
253 	  coord_lat[1] = file_name[2];
254 	  coord_lat[2] = '\0';
255       }
256     else
257 	return GGRAPH_ERROR;
258     if (file_name[3] == 'E')
259 	;
260     else if (file_name[3] == 'W')
261 	lon_sign = -1;
262     else
263 	return GGRAPH_ERROR;
264     if (file_name[4] >= '0' && file_name[4] <= '9')
265 	coord_lon[0] = file_name[4];
266     else
267 	return GGRAPH_ERROR;
268     if (file_name[5] >= '0' && file_name[5] <= '9')
269 	coord_lon[1] = file_name[5];
270     if (file_name[6] >= '0' && file_name[6] <= '9')
271       {
272 	  coord_lon[2] = file_name[6];
273 	  coord_lon[3] = '\0';
274       }
275     else
276 	return GGRAPH_ERROR;
277     if (file_name[7] != '.')
278 	return GGRAPH_ERROR;
279     if (file_name[8] != 'h')
280 	return GGRAPH_ERROR;
281     if (file_name[9] != 'g')
282 	return GGRAPH_ERROR;
283     if (file_name[10] != 't')
284 	return GGRAPH_ERROR;
285 /* ok, it's an HGT file */
286     *lat = atoi (coord_lat) * lat_sign;
287     *lon = atoi (coord_lon) * lon_sign;
288     return GGRAPH_OK;
289 }
290 
291 GGRAPH_DECLARE int
gGraphImageInfosFromHgtFile(const char * path,int lat,int lon,const void ** infos_handle)292 gGraphImageInfosFromHgtFile (const char *path, int lat, int lon,
293 			     const void **infos_handle)
294 {
295 /* retrieving Image infos from HGT file */
296     FILE *in = NULL;
297     gGraphImageInfosPtr infos = NULL;
298     long file_length;
299     int width;
300     int height;
301     double pixel_size;
302     double half_pixel;
303 
304     *infos_handle = NULL;
305 
306 /* attempting to open the image file */
307     in = fopen (path, "rb");
308     if (in == NULL)
309 	return GGRAPH_FILE_OPEN_ERROR;
310 
311 /* retrieving the HGT dimensions */
312     if (fseek (in, 0, SEEK_END) != 0)
313 	return GGRAPH_HGT_CODEC_ERROR;
314     file_length = ftell (in);
315     if (file_length == (1201 * 1201 * sizeof (short)))
316       {
317 	  width = 1201;
318 	  height = 1201;
319 	  pixel_size = 1.0 / 1200.0;
320       }
321     else if (file_length == (3601 * 3601 * sizeof (short)))
322       {
323 	  width = 3601;
324 	  height = 3601;
325 	  pixel_size = 1.0 / 3600.0;
326       }
327     else
328       {
329 	  fclose (in);
330 	  return GGRAPH_HGT_CODEC_ERROR;
331       }
332     fclose (in);
333 
334     infos =
335 	gg_image_infos_create (GG_PIXEL_GRID, width, height, 16, 1,
336 			       GGRAPH_SAMPLE_INT, "WGS 84",
337 			       "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
338     if (!infos)
339 	return GGRAPH_INSUFFICIENT_MEMORY;
340 
341 /* setting up georeferencing infos */
342     half_pixel = pixel_size / 2.0;
343     infos->is_georeferenced = 1;
344     infos->srid = 4326;
345     infos->upper_left_x = (double) lon - half_pixel;
346     infos->upper_left_y = (double) lat + 1.0 + half_pixel;
347     infos->pixel_x_size = pixel_size;
348     infos->pixel_y_size = pixel_size;
349     infos->no_data_value = SHRT_MIN;
350 
351     *infos_handle = infos;
352     return GGRAPH_OK;
353 }
354 
355 GGRAPH_DECLARE int
gGraphCheckBinPath(const char * path,char * hdr_path,int dont_test)356 gGraphCheckBinPath (const char *path, char *hdr_path, int dont_test)
357 {
358 /* checking for BIN+HDR format */
359     char naked_path[1024];
360     int i;
361     int start = 0;
362     FILE *in;
363 
364     *hdr_path = '\0';
365     for (i = strlen (path) - 1; i >= 0; i--)
366       {
367 	  /* attempting to extract the file name */
368 	  if (path[i] == '.')
369 	    {
370 		start = i;
371 		break;
372 	    }
373       }
374     strcpy (naked_path, path);
375     if (strcasecmp (path + start, ".bin") != 0)
376 	return GGRAPH_ERROR;
377     naked_path[start] = '\0';
378     strcat (naked_path, ".hdr");
379     if (dont_test)
380       {
381 	  strcpy (hdr_path, naked_path);
382 	  return GGRAPH_OK;
383       }
384 
385     in = fopen (naked_path, "rb");
386     if (in != NULL)
387       {
388 	  fclose (in);
389 	  strcpy (hdr_path, naked_path);
390 	  return GGRAPH_OK;
391       }
392     naked_path[start] = '\0';
393     strcat (naked_path, ".HDR");
394     in = fopen (naked_path, "rb");
395     if (in != NULL)
396       {
397 	  fclose (in);
398 	  strcpy (hdr_path, naked_path);
399 	  return GGRAPH_OK;
400       }
401 
402     return GGRAPH_ERROR;
403 }
404 
405 GGRAPH_DECLARE int
gGraphCheckFltPath(const char * path,char * hdr_path,int dont_test)406 gGraphCheckFltPath (const char *path, char *hdr_path, int dont_test)
407 {
408 /* checking for FLT+HDR format */
409     char naked_path[1024];
410     int i;
411     int start = 0;
412     FILE *in;
413 
414     *hdr_path = '\0';
415     for (i = strlen (path) - 1; i >= 0; i--)
416       {
417 	  /* attempting to extract the file name */
418 	  if (path[i] == '.')
419 	    {
420 		start = i;
421 		break;
422 	    }
423       }
424     strcpy (naked_path, path);
425     if (strcasecmp (path + start, ".flt") != 0)
426 	return GGRAPH_ERROR;
427     naked_path[start] = '\0';
428     strcat (naked_path, ".hdr");
429     if (dont_test)
430       {
431 	  strcpy (hdr_path, naked_path);
432 	  return GGRAPH_OK;
433       }
434 
435     in = fopen (naked_path, "rb");
436     if (in != NULL)
437       {
438 	  fclose (in);
439 	  strcpy (hdr_path, naked_path);
440 	  return GGRAPH_OK;
441       }
442     naked_path[start] = '\0';
443     strcat (naked_path, ".HDR");
444     in = fopen (naked_path, "rb");
445     if (in != NULL)
446       {
447 	  fclose (in);
448 	  strcpy (hdr_path, naked_path);
449 	  return GGRAPH_OK;
450       }
451 
452     return GGRAPH_ERROR;
453 }
454 
455 GGRAPH_DECLARE int
gGraphCheckDemPath(const char * path,char * hdr_path,int dont_test)456 gGraphCheckDemPath (const char *path, char *hdr_path, int dont_test)
457 {
458 /* checking for DEM+HDR format */
459     char naked_path[1024];
460     int i;
461     int start = 0;
462     FILE *in;
463 
464     *hdr_path = '\0';
465     for (i = strlen (path) - 1; i >= 0; i--)
466       {
467 	  /* attempting to extract the file name */
468 	  if (path[i] == '.')
469 	    {
470 		start = i;
471 		break;
472 	    }
473       }
474     strcpy (naked_path, path);
475     if (strcasecmp (path + start, ".dem") != 0)
476 	return GGRAPH_ERROR;
477     naked_path[start] = '\0';
478     strcat (naked_path, ".hdr");
479     if (dont_test)
480       {
481 	  strcpy (hdr_path, naked_path);
482 	  return GGRAPH_OK;
483       }
484 
485     in = fopen (naked_path, "rb");
486     if (in != NULL)
487       {
488 	  fclose (in);
489 	  strcpy (hdr_path, naked_path);
490 	  return GGRAPH_OK;
491       }
492     naked_path[start] = '\0';
493     strcat (naked_path, ".HDR");
494     in = fopen (naked_path, "rb");
495     if (in != NULL)
496       {
497 	  fclose (in);
498 	  strcpy (hdr_path, naked_path);
499 	  return GGRAPH_OK;
500       }
501 
502     return GGRAPH_ERROR;
503 }
504 
505 GGRAPH_DECLARE int
gGraphCheckAscPath(const char * path)506 gGraphCheckAscPath (const char *path)
507 {
508 /* checking for ASC format */
509     int i;
510     int start = 0;
511 
512     for (i = strlen (path) - 1; i >= 0; i--)
513       {
514 	  /* attempting to extract the file name */
515 	  if (path[i] == '.')
516 	    {
517 		start = i;
518 		break;
519 	    }
520       }
521     if (strcasecmp (path + start, ".asc") != 0)
522 	return GGRAPH_ERROR;
523     return GGRAPH_OK;
524 }
525 
526 static char *
string_tokenizer(char * string,char * delimiters,char ** ptr)527 string_tokenizer (char *string, char *delimiters, char **ptr)
528 {
529 /* breaking a string into distinct tokens */
530     char *start = NULL;
531     char *p;
532     if (*ptr != NULL)
533 	p = *ptr;
534     else
535 	p = string;
536 
537     if (p == NULL)
538 	return NULL;
539 
540     while (1)
541       {
542 	  int sep = 0;
543 	  char *pd = delimiters;
544 
545 	  if (*p == '\0')
546 	    {
547 		/* last token end */
548 		*ptr = p;
549 		break;
550 	    }
551 
552 	  while (*pd != '\0')
553 	    {
554 		if (*p == *pd)
555 		  {
556 		      /* found a separator char */
557 		      sep = 1;
558 		      break;
559 		  }
560 		pd++;
561 	    }
562 	  if (sep)
563 	    {
564 		if (start)
565 		  {
566 		      /* token end */
567 		      *p = '\0';
568 		      *ptr = p + 1;
569 		      break;
570 		  }
571 	    }
572 	  else
573 	    {
574 		if (!start)
575 		  {
576 		      /* token start */
577 		      start = p;
578 		  }
579 	    }
580 	  p++;
581       }
582 
583     return start;
584 }
585 
586 static int
cvtToInt(const char * str,int * value)587 cvtToInt (const char *str, int *value)
588 {
589 /* attempting to convert from string to int */
590     const char *p = str;
591     int error = 0;
592     int digits = 0;
593     int sign = 0;
594     while (*p != '\0')
595       {
596 	  if (*p >= '0' && *p <= '9')
597 	      digits++;
598 	  else if (*p == '-' || *p == '+')
599 	    {
600 		if (digits == 0)
601 		    sign++;
602 		else
603 		    error = 1;
604 	    }
605 	  else
606 	      error = 1;
607 	  p++;
608       }
609     if (digits > 0 && sign < 2 && error == 0)
610       {
611 	  *value = atoi (str);
612 	  return 1;
613       }
614     return 0;
615 }
616 
617 static int
cvtToDouble(const char * str,double * value)618 cvtToDouble (const char *str, double *value)
619 {
620 /* attempting to convert from string to double */
621     const char *p = str;
622     int error = 0;
623     int digits = 0;
624     int comma = 0;
625     int sign = 0;
626     while (*p != '\0')
627       {
628 	  if (*p >= '0' && *p <= '9')
629 	      digits++;
630 	  else if (*p == '.')
631 	      comma++;
632 	  else if (*p == '-' || *p == '+')
633 	    {
634 		if (digits == 0)
635 		    sign++;
636 		else
637 		    error = 1;
638 	    }
639 	  else
640 	      error = 1;
641 	  p++;
642       }
643     if (digits > 0 && sign < 2 && comma < 2 && error == 0)
644       {
645 	  *value = atof (str);
646 	  return 1;
647       }
648     return 0;
649 }
650 
651 static int
parse_binflt_hdr(const char * hdr_path,int * width,int * height,int * bits_per_sample,int * sample,int * endian,double * no_data,double * min,double * max,double * ulx,double * uly,double * pixel_x_size,double * pixel_y_size,int * expected_length)652 parse_binflt_hdr (const char *hdr_path, int *width, int *height,
653 		  int *bits_per_sample, int *sample, int *endian,
654 		  double *no_data, double *min, double *max, double *ulx,
655 		  double *uly, double *pixel_x_size, double *pixel_y_size,
656 		  int *expected_length)
657 {
658 /* parsing an HDR file [BIN or FLT format] */
659     FILE *hdr = NULL;
660     int s_width = INT_MIN;
661     int s_height = INT_MIN;
662     int sample_format = GGRAPH_SAMPLE_UNKNOWN;
663     int sample_bits = INT_MIN;
664     double no_data_value = DBL_MAX;
665     double x_pixel_size = DBL_MAX;
666     double y_pixel_size = DBL_MAX;
667     double lower_left_x = DBL_MAX;
668     double lower_left_y = DBL_MAX;
669     double min_value = DBL_MAX;
670     double max_value = DBL_MIN;
671     int little_endian = 0;
672     int c;
673     int i_tk;
674     char *saveptr;
675     char hdr_buf[1024];
676     char *token;
677     char keyword[1024];
678     char value[1024];
679     char *p_hdr;
680     int cvt_int;
681     double cvt_dbl;
682     int x_centered;
683     int y_centered;
684     double half_pixel;
685 
686 /* opening the HDR header file */
687     hdr = fopen (hdr_path, "rb");
688     if (hdr == NULL)
689 	return 0;
690 
691     p_hdr = hdr_buf;
692     while ((c = getc (hdr)) != EOF)
693       {
694 	  /* parsing the Header file */
695 	  if (c == '\r')
696 	      continue;
697 	  if (c == '\n')
698 	    {
699 		*p_hdr = '\0';
700 		if (*hdr_buf == '\0')
701 		  {
702 		      /* skipping empty lines */
703 		      p_hdr = hdr_buf;
704 		      continue;
705 		  }
706 		/* breaking the string into separate tokens */
707 		i_tk = 0;
708 		saveptr = NULL;
709 		while (1)
710 		  {
711 		      token = string_tokenizer (hdr_buf, " \t", &saveptr);
712 		      if (token == NULL)
713 			  break;
714 		      if (*token == '\0')
715 			  continue;
716 		      if (i_tk == 0)
717 			{
718 			    strcpy (keyword, token);
719 			    i_tk++;
720 			    continue;
721 			}
722 
723 		      strcpy (value, token);
724 		      i_tk++;
725 		  }
726 
727 		if (i_tk != 2)
728 		    goto stop;
729 		if (strcasecmp (keyword, "BYTEORDER") == 0)
730 		  {
731 		      if (strcasecmp (value, "LSBFIRST") == 0)
732 			  little_endian = 1;
733 		      else
734 			  little_endian = 0;
735 		  }
736 		else if (strcasecmp (keyword, "NROWS") == 0)
737 		  {
738 		      if (!cvtToInt (value, &cvt_int))
739 			  goto stop;
740 		      s_height = cvt_int;
741 		  }
742 		else if (strcasecmp (keyword, "NCOLS") == 0)
743 		  {
744 		      if (!cvtToInt (value, &cvt_int))
745 			  goto stop;
746 		      s_width = cvt_int;
747 		  }
748 		else if (strcasecmp (keyword, "NUMBERTYPE") == 0)
749 		  {
750 		      if (strcasecmp (value, "2_BYTE_INTEGER") == 0)
751 			{
752 			    sample_format = GGRAPH_SAMPLE_INT;
753 			    sample_bits = 16;
754 			}
755 		      else if (strcasecmp (value, "4_BYTE_INTEGER") == 0)
756 			{
757 			    sample_format = GGRAPH_SAMPLE_INT;
758 			    sample_bits = 32;
759 			}
760 		      else if (strcasecmp (value, "4_BYTE_FLOAT") == 0)
761 			{
762 			    sample_format = GGRAPH_SAMPLE_FLOAT;
763 			    sample_bits = 32;
764 			}
765 		      else if (strcasecmp (value, "8_BYTE_FLOAT") == 0)
766 			{
767 			    sample_format = GGRAPH_SAMPLE_FLOAT;
768 			    sample_bits = 64;
769 			}
770 		      else
771 			  goto stop;
772 		  }
773 		else if (strcasecmp (keyword, "NODATA_VALUE") == 0)
774 		  {
775 		      if (!cvtToDouble (value, &cvt_dbl))
776 			  goto stop;
777 		      no_data_value = cvt_dbl;
778 		  }
779 		else if (strcasecmp (keyword, "XLLCENTER") == 0)
780 		  {
781 		      if (!cvtToDouble (value, &cvt_dbl))
782 			  goto stop;
783 		      lower_left_x = cvt_dbl;
784 		      x_centered = 1;
785 		  }
786 		else if (strcasecmp (keyword, "XLLCORNER") == 0)
787 		  {
788 		      if (!cvtToDouble (value, &cvt_dbl))
789 			  goto stop;
790 		      lower_left_x = cvt_dbl;
791 		      x_centered = 0;
792 		  }
793 		else if (strcasecmp (keyword, "YLLCENTER") == 0)
794 		  {
795 		      if (!cvtToDouble (value, &cvt_dbl))
796 			  goto stop;
797 		      lower_left_y = cvt_dbl;
798 		      y_centered = 1;
799 		  }
800 		else if (strcasecmp (keyword, "YLLCORNER") == 0)
801 		  {
802 		      if (!cvtToDouble (value, &cvt_dbl))
803 			  goto stop;
804 		      lower_left_y = cvt_dbl;
805 		      y_centered = 0;
806 		  }
807 		else if (strcasecmp (keyword, "CELLSIZE") == 0)
808 		  {
809 		      if (!cvtToDouble (value, &cvt_dbl))
810 			  goto stop;
811 		      x_pixel_size = cvt_dbl;
812 		      y_pixel_size = cvt_dbl;
813 		  }
814 		else if (strcasecmp (keyword, "ZUNITS") == 0)
815 		  {
816 		      /* ignoring */
817 		  }
818 		else if (strcasecmp (keyword, "MIN_VALUE") == 0)
819 		  {
820 		      if (!cvtToDouble (value, &cvt_dbl))
821 			  goto stop;
822 		      min_value = cvt_dbl;
823 		  }
824 		else if (strcasecmp (keyword, "MAX_VALUE") == 0)
825 		  {
826 		      if (!cvtToDouble (value, &cvt_dbl))
827 			  goto stop;
828 		      max_value = cvt_dbl;
829 		  }
830 		else
831 		  {
832 		      /* unrecognized tag */
833 		      goto stop;
834 		  }
835 		p_hdr = hdr_buf;
836 		continue;
837 	    }
838 	  *p_hdr++ = c;
839 	  if (p_hdr - hdr_buf > 1024)
840 	      goto stop;
841       }
842     fclose (hdr);
843     hdr = NULL;
844 
845     if (s_width <= 0 || s_height <= 0 || sample_bits <= 0)
846 	goto stop;
847     if (sample_format == GGRAPH_SAMPLE_UNKNOWN)
848 	goto stop;
849     if (no_data_value == INT_MAX)
850 	goto stop;
851     if (x_pixel_size == DBL_MAX || y_pixel_size == DBL_MAX)
852 	goto stop;
853     if (lower_left_x == DBL_MAX || lower_left_y == DBL_MAX)
854 	goto stop;
855     if (min_value == DBL_MAX || max_value == DBL_MIN)
856 	goto stop;
857 
858     *width = s_width;
859     *height = s_height;
860     *sample = sample_format;
861     *bits_per_sample = sample_bits;
862     *endian = little_endian;
863     *no_data = no_data_value;
864     *ulx = lower_left_x;
865     half_pixel = x_pixel_size / 2.0;
866     if (x_centered)
867 	*ulx -= half_pixel;
868     *uly = lower_left_y + ((double) s_height * y_pixel_size);
869     half_pixel = y_pixel_size / 2.0;
870     if (y_centered)
871 	*uly += half_pixel;
872     *pixel_x_size = x_pixel_size;
873     *pixel_y_size = y_pixel_size;
874     *min = min_value;
875     *max = max_value;
876     if (sample_bits == 16)
877 	*expected_length = s_width * s_height * 2;
878     else if (sample_bits == 32)
879 	*expected_length = s_width * s_height * 4;
880     else if (sample_bits == 64)
881 	*expected_length = s_width * s_height * 8;
882     else
883 	*expected_length = -1;
884     return 1;
885 
886   stop:
887     if (hdr)
888 	fclose (hdr);
889     return 0;
890 }
891 
892 GGRAPH_DECLARE int
gGraphImageInfosFromBinFile(const char * path,const char * hdr_path,const void ** infos_handle)893 gGraphImageInfosFromBinFile (const char *path, const char *hdr_path,
894 			     const void **infos_handle)
895 {
896 /* retrieving Image infos from BIN+HDR file */
897     FILE *in = NULL;
898     gGraphImageInfosPtr infos = NULL;
899     long file_length;
900     int expected_length;
901     int width;
902     int height;
903     double ulx;
904     double uly;
905     double pixel_x_size;
906     double pixel_y_size;
907     int sample;
908     int bits_per_sample;
909     int endian;
910     double no_data;
911     double min;
912     double max;
913 
914     *infos_handle = NULL;
915 
916     if (!parse_binflt_hdr
917 	(hdr_path, &width, &height, &bits_per_sample, &sample, &endian,
918 	 &no_data, &min, &max, &ulx, &uly, &pixel_x_size, &pixel_y_size,
919 	 &expected_length))
920 	return GGRAPH_BIN_CODEC_ERROR;
921 
922 /* attempting to open the image file */
923     in = fopen (path, "rb");
924     if (in == NULL)
925 	return GGRAPH_FILE_OPEN_ERROR;
926 
927 /* retrieving the BIN dimensions */
928     if (fseek (in, 0, SEEK_END) != 0)
929 	return GGRAPH_BIN_CODEC_ERROR;
930     file_length = ftell (in);
931     if (file_length != expected_length)
932       {
933 	  fclose (in);
934 	  return GGRAPH_BIN_CODEC_ERROR;
935       }
936     fclose (in);
937 
938     infos =
939 	gg_image_infos_create (GG_PIXEL_GRID, width, height, bits_per_sample, 1,
940 			       sample, NULL, NULL);
941     if (!infos)
942 	return GGRAPH_INSUFFICIENT_MEMORY;
943 
944 /* setting up georeferencing infos */
945     infos->is_georeferenced = 1;
946     infos->upper_left_x = ulx;
947     infos->upper_left_y = uly;
948     infos->pixel_x_size = pixel_x_size;
949     infos->pixel_y_size = pixel_y_size;
950     infos->no_data_value = no_data;
951     infos->min_value = min;
952     infos->max_value = max;
953 
954     *infos_handle = infos;
955     return GGRAPH_OK;
956 }
957 
958 GGRAPH_DECLARE int
gGraphImageInfosFromFltFile(const char * path,const char * hdr_path,const void ** infos_handle)959 gGraphImageInfosFromFltFile (const char *path, const char *hdr_path,
960 			     const void **infos_handle)
961 {
962 /* retrieving Image infos from FLT+HDR file */
963     FILE *in = NULL;
964     gGraphImageInfosPtr infos = NULL;
965     long file_length;
966     int expected_length;
967     int width;
968     int height;
969     double ulx;
970     double uly;
971     double pixel_x_size;
972     double pixel_y_size;
973     int sample;
974     int bits_per_sample;
975     int endian;
976     double no_data;
977     double min;
978     double max;
979 
980     *infos_handle = NULL;
981 
982     if (!parse_binflt_hdr
983 	(hdr_path, &width, &height, &bits_per_sample, &sample, &endian,
984 	 &no_data, &min, &max, &ulx, &uly, &pixel_x_size, &pixel_y_size,
985 	 &expected_length))
986 	return GGRAPH_FLT_CODEC_ERROR;
987 
988 /* attempting to open the image file */
989     in = fopen (path, "rb");
990     if (in == NULL)
991 	return GGRAPH_FILE_OPEN_ERROR;
992 
993 /* retrieving the FLT dimensions */
994     if (fseek (in, 0, SEEK_END) != 0)
995 	return GGRAPH_FLT_CODEC_ERROR;
996     file_length = ftell (in);
997     if (file_length != expected_length)
998       {
999 	  fclose (in);
1000 	  return GGRAPH_FLT_CODEC_ERROR;
1001       }
1002     fclose (in);
1003 
1004     infos =
1005 	gg_image_infos_create (GG_PIXEL_GRID, width, height, bits_per_sample, 1,
1006 			       sample, NULL, NULL);
1007     if (!infos)
1008 	return GGRAPH_INSUFFICIENT_MEMORY;
1009 
1010 /* setting up georeferencing infos */
1011     infos->is_georeferenced = 1;
1012     infos->upper_left_x = ulx;
1013     infos->upper_left_y = uly;
1014     infos->pixel_x_size = pixel_x_size;
1015     infos->pixel_y_size = pixel_y_size;
1016     infos->no_data_value = no_data;
1017     infos->min_value = min;
1018     infos->max_value = max;
1019 
1020     *infos_handle = infos;
1021     return GGRAPH_OK;
1022 }
1023 
1024 static int
parse_dem_hdr(const char * hdr_path,int * width,int * height,int * bits_per_sample,int * sample,int * endian,double * no_data,double * ulx,double * uly,double * pixel_x_size,double * pixel_y_size,int * expected_length)1025 parse_dem_hdr (const char *hdr_path, int *width, int *height,
1026 	       int *bits_per_sample, int *sample, int *endian, double *no_data,
1027 	       double *ulx, double *uly, double *pixel_x_size,
1028 	       double *pixel_y_size, int *expected_length)
1029 {
1030 /* parsing an HDR file [DEM format] */
1031     FILE *hdr = NULL;
1032     int s_width = INT_MIN;
1033     int s_height = INT_MIN;
1034     int sample_format = GGRAPH_SAMPLE_UNKNOWN;
1035     int sample_bits = INT_MIN;
1036     double no_data_value = DBL_MAX;
1037     double x_pixel_size = DBL_MAX;
1038     double y_pixel_size = DBL_MAX;
1039     double upper_left_x = DBL_MAX;
1040     double upper_left_y = DBL_MAX;
1041     int band_row_bytes = INT_MIN;
1042     int total_row_bytes = INT_MIN;
1043     int little_endian = 0;
1044     int c;
1045     int i_tk;
1046     char *saveptr;
1047     char hdr_buf[1024];
1048     char *token;
1049     char keyword[1024];
1050     char value[1024];
1051     char *p_hdr;
1052     int cvt_int;
1053     double cvt_dbl;
1054 
1055 /* opening the HDR header file */
1056     hdr = fopen (hdr_path, "rb");
1057     if (hdr == NULL)
1058 	return 0;
1059 
1060     p_hdr = hdr_buf;
1061     while ((c = getc (hdr)) != EOF)
1062       {
1063 	  /* parsing the Header file */
1064 	  if (c == '\r' || c == '\n')
1065 	    {
1066 		*p_hdr = '\0';
1067 		if (*hdr_buf == '\0')
1068 		  {
1069 		      /* skipping empty lines */
1070 		      p_hdr = hdr_buf;
1071 		      continue;
1072 		  }
1073 		/* breaking the string into separate tokens */
1074 		i_tk = 0;
1075 		saveptr = NULL;
1076 		while (1)
1077 		  {
1078 		      token = string_tokenizer (hdr_buf, " \t", &saveptr);
1079 		      if (token == NULL)
1080 			  break;
1081 		      if (*token == '\0')
1082 			  continue;
1083 		      if (i_tk == 0)
1084 			{
1085 			    strcpy (keyword, token);
1086 			    i_tk++;
1087 			    continue;
1088 			}
1089 
1090 		      strcpy (value, token);
1091 		      i_tk++;
1092 		  }
1093 
1094 		if (i_tk != 2)
1095 		    goto stop;
1096 		if (strcasecmp (keyword, "BYTEORDER") == 0)
1097 		  {
1098 		      if (strcasecmp (value, "M") == 0)
1099 			  little_endian = 0;
1100 		      else
1101 			  little_endian = 1;
1102 		  }
1103 		else if (strcasecmp (keyword, "LAYOUT") == 0)
1104 		  {
1105 		      /* Bands organization: only Band Interleave by Line is supported */
1106 		      if (strcasecmp (value, "BIL") != 0)
1107 			  goto stop;
1108 		  }
1109 		else if (strcasecmp (keyword, "NROWS") == 0)
1110 		  {
1111 		      if (!cvtToInt (value, &cvt_int))
1112 			  goto stop;
1113 		      s_height = cvt_int;
1114 		  }
1115 		else if (strcasecmp (keyword, "NCOLS") == 0)
1116 		  {
1117 		      if (!cvtToInt (value, &cvt_int))
1118 			  goto stop;
1119 		      s_width = cvt_int;
1120 		  }
1121 		else if (strcasecmp (keyword, "NBANDS") == 0)
1122 		  {
1123 		      /* expected: 1 band */
1124 		      if (!cvtToInt (value, &cvt_int))
1125 			  goto stop;
1126 		      if (cvt_int != 1)
1127 			  goto stop;
1128 		  }
1129 		else if (strcasecmp (keyword, "NBITS") == 0)
1130 		  {
1131 		      /* expected: 16 or 32 bit ints */
1132 		      if (!cvtToInt (value, &cvt_int))
1133 			  goto stop;
1134 		      if (cvt_int == 16)
1135 			{
1136 			    sample_format = GGRAPH_SAMPLE_INT;
1137 			    sample_bits = 16;
1138 			}
1139 		      else if (cvt_int == 32)
1140 			{
1141 			    sample_format = GGRAPH_SAMPLE_INT;
1142 			    sample_bits = 32;
1143 			}
1144 		      else
1145 			  goto stop;
1146 		  }
1147 		else if (strcasecmp (keyword, "BANDROWBYTES") == 0)
1148 		  {
1149 		      if (!cvtToInt (value, &cvt_int))
1150 			  goto stop;
1151 		      band_row_bytes = cvt_int;
1152 		  }
1153 		else if (strcasecmp (keyword, "TOTALROWBYTES") == 0)
1154 		  {
1155 		      if (!cvtToInt (value, &cvt_int))
1156 			  goto stop;
1157 		      total_row_bytes = cvt_int;
1158 		  }
1159 		else if (strcasecmp (keyword, "BANDGAPBYTES") == 0)
1160 		  {
1161 		      /* expected: 0 bytes between bands */
1162 		      if (!cvtToInt (value, &cvt_int))
1163 			  goto stop;
1164 		      if (cvt_int != 0)
1165 			  goto stop;
1166 		  }
1167 		else if (strcasecmp (keyword, "NODATA") == 0)
1168 		  {
1169 		      if (!cvtToInt (value, &cvt_int))
1170 			  goto stop;
1171 		      no_data_value = cvt_int;
1172 		  }
1173 		else if (strcasecmp (keyword, "ULXMAP") == 0)
1174 		  {
1175 		      if (!cvtToDouble (value, &cvt_dbl))
1176 			  goto stop;
1177 		      upper_left_x = cvt_dbl;
1178 		  }
1179 		else if (strcasecmp (keyword, "ULYMAP") == 0)
1180 		  {
1181 		      if (!cvtToDouble (value, &cvt_dbl))
1182 			  goto stop;
1183 		      upper_left_y = cvt_dbl;
1184 		  }
1185 		else if (strcasecmp (keyword, "XDIM") == 0)
1186 		  {
1187 		      if (!cvtToDouble (value, &cvt_dbl))
1188 			  goto stop;
1189 		      x_pixel_size = cvt_dbl;
1190 		  }
1191 		else if (strcasecmp (keyword, "YDIM") == 0)
1192 		  {
1193 		      if (!cvtToDouble (value, &cvt_dbl))
1194 			  goto stop;
1195 		      y_pixel_size = cvt_dbl;
1196 		  }
1197 		else
1198 		  {
1199 		      /* unrecognized tag */
1200 		      goto stop;
1201 		  }
1202 		p_hdr = hdr_buf;
1203 		continue;
1204 	    }
1205 	  *p_hdr++ = c;
1206 	  if (p_hdr - hdr_buf > 1024)
1207 	      goto stop;
1208       }
1209     fclose (hdr);
1210     hdr = NULL;
1211 
1212     if (s_width <= 0 || s_height <= 0 || sample_bits <= 0)
1213 	goto stop;
1214     if (sample_format == GGRAPH_SAMPLE_UNKNOWN)
1215 	goto stop;
1216     if (no_data_value == INT_MAX)
1217 	goto stop;
1218     if (x_pixel_size == DBL_MAX || y_pixel_size == DBL_MAX)
1219 	goto stop;
1220     if (upper_left_x == DBL_MAX || upper_left_y == DBL_MAX)
1221 	goto stop;
1222     if (sample_bits == 16)
1223       {
1224 	  if (2 * s_width != band_row_bytes)
1225 	      goto stop;
1226 	  if (2 * s_width != total_row_bytes)
1227 	      goto stop;
1228       }
1229     if (sample_bits == 32)
1230       {
1231 	  if (4 * s_width != band_row_bytes)
1232 	      goto stop;
1233 	  if (4 * s_width != total_row_bytes)
1234 	      goto stop;
1235       }
1236     *width = s_width;
1237     *height = s_height;
1238     *sample = sample_format;
1239     *bits_per_sample = sample_bits;
1240     *endian = little_endian;
1241     *no_data = no_data_value;
1242     *ulx = upper_left_x;
1243     *uly = upper_left_y;
1244     *pixel_x_size = x_pixel_size;
1245     *pixel_y_size = y_pixel_size;
1246     if (sample_bits == 16)
1247 	*expected_length = s_width * s_height * 2;
1248     else if (sample_bits == 32)
1249 	*expected_length = s_width * s_height * 4;
1250     else
1251 	*expected_length = -1;
1252     return 1;
1253 
1254   stop:
1255     if (hdr)
1256 	fclose (hdr);
1257     return 0;
1258 }
1259 
1260 GGRAPH_DECLARE int
gGraphImageInfosFromDemFile(const char * path,const char * hdr_path,const void ** infos_handle)1261 gGraphImageInfosFromDemFile (const char *path, const char *hdr_path,
1262 			     const void **infos_handle)
1263 {
1264 /* retrieving Image infos from DEM+HDR file */
1265     FILE *in = NULL;
1266     gGraphImageInfosPtr infos = NULL;
1267     long file_length;
1268     int expected_length;
1269     int width;
1270     int height;
1271     double ulx;
1272     double uly;
1273     double pixel_x_size;
1274     double pixel_y_size;
1275     int sample;
1276     int bits_per_sample;
1277     int endian;
1278     double no_data;
1279 
1280     *infos_handle = NULL;
1281 
1282     if (!parse_dem_hdr
1283 	(hdr_path, &width, &height, &bits_per_sample, &sample, &endian,
1284 	 &no_data, &ulx, &uly, &pixel_x_size, &pixel_y_size, &expected_length))
1285 	return GGRAPH_FLT_CODEC_ERROR;
1286 
1287 /* attempting to open the image file */
1288     in = fopen (path, "rb");
1289     if (in == NULL)
1290 	return GGRAPH_FILE_OPEN_ERROR;
1291 
1292 /* retrieving the FLT dimensions */
1293     if (fseek (in, 0, SEEK_END) != 0)
1294 	return GGRAPH_FLT_CODEC_ERROR;
1295     file_length = ftell (in);
1296     if (file_length != expected_length)
1297       {
1298 	  fclose (in);
1299 	  return GGRAPH_FLT_CODEC_ERROR;
1300       }
1301     fclose (in);
1302 
1303     infos =
1304 	gg_image_infos_create (GG_PIXEL_GRID, width, height, bits_per_sample, 1,
1305 			       sample, NULL, NULL);
1306     if (!infos)
1307 	return GGRAPH_INSUFFICIENT_MEMORY;
1308 
1309 /* setting up georeferencing infos */
1310     infos->is_georeferenced = 1;
1311     infos->upper_left_x = ulx;
1312     infos->upper_left_y = uly;
1313     infos->pixel_x_size = pixel_x_size;
1314     infos->pixel_y_size = pixel_y_size;
1315     infos->no_data_value = no_data;
1316 
1317     *infos_handle = infos;
1318     return GGRAPH_OK;
1319 }
1320 
1321 static int
parse_asc_hdr(const char * path,FILE * file,int * width,int * height,double * ulx,double * uly,double * pixel_x_size,double * pixel_y_size,double * no_data)1322 parse_asc_hdr (const char *path, FILE * file, int *width, int *height,
1323 	       double *ulx, double *uly, double *pixel_x_size,
1324 	       double *pixel_y_size, double *no_data)
1325 {
1326 /* parsing an ASC file [ASCII GRID format] */
1327     FILE *hdr = NULL;
1328     int s_width = INT_MIN;
1329     int s_height = INT_MIN;
1330     double x_pixel_size = DBL_MAX;
1331     double y_pixel_size = DBL_MAX;
1332     double lower_left_x = DBL_MAX;
1333     double lower_left_y = DBL_MAX;
1334     double no_data_value = DBL_MAX;
1335     int c;
1336     int i_tk;
1337     char *saveptr;
1338     char hdr_buf[1024];
1339     char *token;
1340     char keyword[1024];
1341     char value[1024];
1342     char *p_hdr;
1343     int cvt_int;
1344     double cvt_dbl;
1345     int x_centered;
1346     int y_centered;
1347     double half_pixel;
1348     int row;
1349 
1350     if (path != NULL)
1351       {
1352 	  /* opening the ASC header file */
1353 	  hdr = fopen (path, "rb");
1354       }
1355     else
1356 	hdr = file;
1357     if (hdr == NULL)
1358 	return 0;
1359     row = 0;
1360     p_hdr = hdr_buf;
1361     while ((c = getc (hdr)) != EOF)
1362       {
1363 	  /* parsing the Header file */
1364 	  if (c == '\r')
1365 	      continue;
1366 	  if (c == '\n')
1367 	    {
1368 		row++;
1369 		*p_hdr = '\0';
1370 		if (*hdr_buf == '\0')
1371 		  {
1372 		      /* skipping empty lines */
1373 		      p_hdr = hdr_buf;
1374 		      continue;
1375 		  }
1376 		/* breaking the string into separate tokens */
1377 		i_tk = 0;
1378 		saveptr = NULL;
1379 		while (1)
1380 		  {
1381 		      token = string_tokenizer (hdr_buf, " \t", &saveptr);
1382 		      if (token == NULL)
1383 			  break;
1384 		      if (*token == '\0')
1385 			  continue;
1386 		      if (i_tk == 0)
1387 			{
1388 			    strcpy (keyword, token);
1389 			    i_tk++;
1390 			    continue;
1391 			}
1392 
1393 		      strcpy (value, token);
1394 		      i_tk++;
1395 		  }
1396 
1397 		if (i_tk != 2)
1398 		    goto stop;
1399 		if (strcasecmp (keyword, "NROWS") == 0)
1400 		  {
1401 		      if (!cvtToInt (value, &cvt_int))
1402 			  goto stop;
1403 		      s_height = cvt_int;
1404 		  }
1405 		else if (strcasecmp (keyword, "NCOLS") == 0)
1406 		  {
1407 		      if (!cvtToInt (value, &cvt_int))
1408 			  goto stop;
1409 		      s_width = cvt_int;
1410 		  }
1411 		else if (strcasecmp (keyword, "NODATA_VALUE") == 0)
1412 		  {
1413 		      if (!cvtToDouble (value, &cvt_dbl))
1414 			  goto stop;
1415 		      no_data_value = cvt_dbl;
1416 		  }
1417 		else if (strcasecmp (keyword, "XLLCENTER") == 0)
1418 		  {
1419 		      if (!cvtToDouble (value, &cvt_dbl))
1420 			  goto stop;
1421 		      lower_left_x = cvt_dbl;
1422 		      x_centered = 1;
1423 		  }
1424 		else if (strcasecmp (keyword, "XLLCORNER") == 0)
1425 		  {
1426 		      if (!cvtToDouble (value, &cvt_dbl))
1427 			  goto stop;
1428 		      lower_left_x = cvt_dbl;
1429 		      x_centered = 0;
1430 		  }
1431 		else if (strcasecmp (keyword, "YLLCENTER") == 0)
1432 		  {
1433 		      if (!cvtToDouble (value, &cvt_dbl))
1434 			  goto stop;
1435 		      lower_left_y = cvt_dbl;
1436 		      y_centered = 1;
1437 		  }
1438 		else if (strcasecmp (keyword, "YLLCORNER") == 0)
1439 		  {
1440 		      if (!cvtToDouble (value, &cvt_dbl))
1441 			  goto stop;
1442 		      lower_left_y = cvt_dbl;
1443 		      y_centered = 0;
1444 		  }
1445 		else if (strcasecmp (keyword, "CELLSIZE") == 0)
1446 		  {
1447 		      if (!cvtToDouble (value, &cvt_dbl))
1448 			  goto stop;
1449 		      x_pixel_size = cvt_dbl;
1450 		      y_pixel_size = x_pixel_size;
1451 		  }
1452 		else
1453 		  {
1454 		      /* unrecognized tag */
1455 		      goto stop;
1456 		  }
1457 		p_hdr = hdr_buf;
1458 		if (row == 6)
1459 		    break;
1460 		continue;
1461 	    }
1462 	  *p_hdr++ = c;
1463 	  if (p_hdr - hdr_buf > 1024)
1464 	      goto stop;
1465       }
1466     if (path != NULL)
1467 	fclose (hdr);
1468     hdr = NULL;
1469 
1470     if (s_width <= 0 || s_height <= 0)
1471 	goto stop;
1472     if (no_data_value == INT_MAX)
1473 	goto stop;
1474     if (x_pixel_size == DBL_MAX || y_pixel_size == DBL_MAX)
1475 	goto stop;
1476     if (lower_left_x == DBL_MAX || lower_left_y == DBL_MAX)
1477 	goto stop;
1478     *width = s_width;
1479     *height = s_height;
1480     *no_data = no_data_value;
1481     *ulx = lower_left_x;
1482     half_pixel = x_pixel_size / 2.0;
1483     if (x_centered)
1484 	*ulx -= half_pixel;
1485     *uly = lower_left_y + ((double) s_height * y_pixel_size);
1486     half_pixel = y_pixel_size / 2.0;
1487     if (y_centered)
1488 	*uly += half_pixel;
1489     *pixel_x_size = x_pixel_size;
1490     *pixel_y_size = y_pixel_size;
1491     return 1;
1492 
1493   stop:
1494     if (path != NULL)
1495       {
1496 	  if (hdr)
1497 	      fclose (hdr);
1498       }
1499     return 0;
1500 }
1501 
1502 GGRAPH_DECLARE int
gGraphImageInfosFromAscFile(const char * path,const void ** infos_handle)1503 gGraphImageInfosFromAscFile (const char *path, const void **infos_handle)
1504 {
1505 /* retrieving Image infos from ASC file */
1506     gGraphImageInfosPtr infos = NULL;
1507     int width;
1508     int height;
1509     double ulx;
1510     double uly;
1511     double pixel_x_size;
1512     double pixel_y_size;
1513     double no_data;
1514 
1515     *infos_handle = NULL;
1516 
1517     if (!parse_asc_hdr
1518 	(path, NULL, &width, &height, &ulx, &uly, &pixel_x_size, &pixel_y_size,
1519 	 &no_data))
1520 	return GGRAPH_ASCII_CODEC_ERROR;
1521 
1522     infos =
1523 	gg_image_infos_create (GG_PIXEL_GRID, width, height, 32, 1,
1524 			       GGRAPH_SAMPLE_FLOAT, NULL, NULL);
1525     if (!infos)
1526 	return GGRAPH_INSUFFICIENT_MEMORY;
1527 
1528 /* setting up georeferencing infos */
1529     infos->is_georeferenced = 1;
1530     infos->upper_left_x = ulx;
1531     infos->upper_left_y = uly;
1532     infos->pixel_x_size = pixel_x_size;
1533     infos->pixel_y_size = pixel_y_size;
1534     infos->no_data_value = no_data;
1535 
1536     *infos_handle = infos;
1537     return GGRAPH_OK;
1538 }
1539 
1540 GGRAPH_PRIVATE int
gg_image_strip_prepare_from_bin_hdr(FILE * in,const char * hdr_path,gGraphStripImagePtr * image_handle)1541 gg_image_strip_prepare_from_bin_hdr (FILE * in, const char *hdr_path,
1542 				     gGraphStripImagePtr * image_handle)
1543 {
1544 /* preparing to decode an BIN-GRID [by strips] */
1545     gGraphStripImagePtr img = NULL;
1546     struct grid_codec_data *grid_codec = NULL;
1547     long file_length;
1548     int expected_length;
1549     int width;
1550     int height;
1551     double ulx;
1552     double uly;
1553     double pixel_x_size;
1554     double pixel_y_size;
1555     int sample;
1556     int bits_per_sample;
1557     int endian;
1558     double no_data;
1559     double min;
1560     double max;
1561     int buf_size;
1562     void *grid_buffer = NULL;
1563     int ret = GGRAPH_BIN_CODEC_ERROR;
1564     *image_handle = NULL;
1565 
1566     if (!parse_binflt_hdr
1567 	(hdr_path, &width, &height, &bits_per_sample, &sample, &endian,
1568 	 &no_data, &min, &max, &ulx, &uly, &pixel_x_size, &pixel_y_size,
1569 	 &expected_length))
1570 	return GGRAPH_BIN_CODEC_ERROR;
1571 
1572 /* retrieving the BIN dimensions */
1573     if (fseek (in, 0, SEEK_END) != 0)
1574 	return GGRAPH_BIN_CODEC_ERROR;
1575     file_length = ftell (in);
1576     if (file_length != expected_length)
1577 	return GGRAPH_BIN_CODEC_ERROR;
1578 
1579     img =
1580 	gg_strip_image_create (in, GGRAPH_IMAGE_BIN_HDR, GG_PIXEL_GRID, width,
1581 			       height, bits_per_sample, 1, sample, NULL, NULL);
1582     if (!img)
1583       {
1584 	  ret = GGRAPH_INSUFFICIENT_MEMORY;
1585 	  goto error;
1586       }
1587 
1588 /* setting up georeferencing infos */
1589     img->is_georeferenced = 1;
1590     img->upper_left_x = ulx;
1591     img->upper_left_y = uly;
1592     img->pixel_x_size = pixel_x_size;
1593     img->pixel_y_size = pixel_y_size;
1594     img->no_data_value = no_data;
1595     img->min_value = min;
1596     img->max_value = max;
1597 
1598 /* setting up the GRID codec struct */
1599     grid_codec = malloc (sizeof (struct grid_codec_data));
1600     if (!grid_codec)
1601 	goto error;
1602     grid_codec->grid_type = GRID_BIN_HDR;
1603     grid_codec->is_writer = 0;
1604     grid_codec->grid_buffer = NULL;
1605     grid_codec->row_offsets = NULL;
1606     grid_codec->little_endian = endian;
1607     img->codec_data = grid_codec;
1608 
1609 /* allocating the GRID read buffer */
1610     if (sample == GGRAPH_SAMPLE_INT)
1611       {
1612 	  if (bits_per_sample == 16)
1613 	      buf_size = sizeof (short) * width;
1614 	  if (bits_per_sample == 32)
1615 	      buf_size = sizeof (int) * width;
1616       }
1617     if (sample == GGRAPH_SAMPLE_FLOAT)
1618       {
1619 	  if (bits_per_sample == 32)
1620 	      buf_size = sizeof (float) * width;
1621 	  if (bits_per_sample == 64)
1622 	      buf_size = sizeof (double) * width;
1623       }
1624     grid_buffer = malloc (buf_size);
1625     if (!grid_buffer)
1626 	goto error;
1627     grid_codec->grid_buffer = grid_buffer;
1628 
1629     *image_handle = img;
1630     return GGRAPH_OK;
1631 
1632   error:
1633     if (img)
1634 	gGraphDestroyImage (img);
1635     return ret;
1636 }
1637 
1638 GGRAPH_PRIVATE int
gg_image_strip_prepare_from_flt_hdr(FILE * in,const char * hdr_path,gGraphStripImagePtr * image_handle)1639 gg_image_strip_prepare_from_flt_hdr (FILE * in, const char *hdr_path,
1640 				     gGraphStripImagePtr * image_handle)
1641 {
1642 /* preparing to decode an FLT-GRID [by strips] */
1643     gGraphStripImagePtr img = NULL;
1644     struct grid_codec_data *grid_codec = NULL;
1645     long file_length;
1646     int expected_length;
1647     int width;
1648     int height;
1649     double ulx;
1650     double uly;
1651     double pixel_x_size;
1652     double pixel_y_size;
1653     int sample;
1654     int bits_per_sample;
1655     int endian;
1656     double no_data;
1657     double min;
1658     double max;
1659     int buf_size;
1660     void *grid_buffer = NULL;
1661     int ret = GGRAPH_FLT_CODEC_ERROR;
1662     *image_handle = NULL;
1663 
1664     if (!parse_binflt_hdr
1665 	(hdr_path, &width, &height, &bits_per_sample, &sample, &endian,
1666 	 &no_data, &min, &max, &ulx, &uly, &pixel_x_size, &pixel_y_size,
1667 	 &expected_length))
1668 	return GGRAPH_FLT_CODEC_ERROR;
1669 
1670 /* retrieving the FLT dimensions */
1671     if (fseek (in, 0, SEEK_END) != 0)
1672 	return GGRAPH_FLT_CODEC_ERROR;
1673     file_length = ftell (in);
1674     if (file_length != expected_length)
1675 	return GGRAPH_FLT_CODEC_ERROR;
1676 
1677     img =
1678 	gg_strip_image_create (in, GGRAPH_IMAGE_FLT_HDR, GG_PIXEL_GRID, width,
1679 			       height, bits_per_sample, 1, sample, NULL, NULL);
1680     if (!img)
1681       {
1682 	  ret = GGRAPH_INSUFFICIENT_MEMORY;
1683 	  goto error;
1684       }
1685 
1686 /* setting up georeferencing infos */
1687     img->is_georeferenced = 1;
1688     img->upper_left_x = ulx;
1689     img->upper_left_y = uly;
1690     img->pixel_x_size = pixel_x_size;
1691     img->pixel_y_size = pixel_y_size;
1692     img->no_data_value = no_data;
1693     img->min_value = min;
1694     img->max_value = max;
1695 
1696 /* setting up the GRID codec struct */
1697     grid_codec = malloc (sizeof (struct grid_codec_data));
1698     if (!grid_codec)
1699 	goto error;
1700     grid_codec->grid_type = GRID_FLT_HDR;
1701     grid_codec->is_writer = 0;
1702     grid_codec->grid_buffer = NULL;
1703     grid_codec->row_offsets = NULL;
1704     grid_codec->little_endian = endian;
1705     img->codec_data = grid_codec;
1706 
1707 /* allocating the GRID read buffer */
1708     if (sample == GGRAPH_SAMPLE_INT)
1709       {
1710 	  if (bits_per_sample == 16)
1711 	      buf_size = sizeof (short) * width;
1712 	  if (bits_per_sample == 32)
1713 	      buf_size = sizeof (int) * width;
1714       }
1715     if (sample == GGRAPH_SAMPLE_FLOAT)
1716       {
1717 	  if (bits_per_sample == 32)
1718 	      buf_size = sizeof (float) * width;
1719 	  if (bits_per_sample == 64)
1720 	      buf_size = sizeof (double) * width;
1721       }
1722     grid_buffer = malloc (buf_size);
1723     if (!grid_buffer)
1724 	goto error;
1725     grid_codec->grid_buffer = grid_buffer;
1726 
1727     *image_handle = img;
1728     return GGRAPH_OK;
1729 
1730   error:
1731     if (img)
1732 	gGraphDestroyImage (img);
1733     return ret;
1734 }
1735 
1736 GGRAPH_PRIVATE int
gg_image_strip_prepare_from_dem_hdr(FILE * in,const char * hdr_path,gGraphStripImagePtr * image_handle)1737 gg_image_strip_prepare_from_dem_hdr (FILE * in, const char *hdr_path,
1738 				     gGraphStripImagePtr * image_handle)
1739 {
1740 /* preparing to decode an DEM-GRID [by strips] */
1741     gGraphStripImagePtr img = NULL;
1742     struct grid_codec_data *grid_codec = NULL;
1743     long file_length;
1744     int expected_length;
1745     int width;
1746     int height;
1747     double ulx;
1748     double uly;
1749     double pixel_x_size;
1750     double pixel_y_size;
1751     int sample;
1752     int bits_per_sample;
1753     int endian;
1754     double no_data;
1755     int buf_size;
1756     void *grid_buffer = NULL;
1757     int ret = GGRAPH_DEM_CODEC_ERROR;
1758     *image_handle = NULL;
1759 
1760     if (!parse_dem_hdr
1761 	(hdr_path, &width, &height, &bits_per_sample, &sample, &endian,
1762 	 &no_data, &ulx, &uly, &pixel_x_size, &pixel_y_size, &expected_length))
1763 	return GGRAPH_DEM_CODEC_ERROR;
1764 
1765 /* retrieving the DEM dimensions */
1766     if (fseek (in, 0, SEEK_END) != 0)
1767 	return GGRAPH_DEM_CODEC_ERROR;
1768     file_length = ftell (in);
1769     if (file_length != expected_length)
1770 	return GGRAPH_DEM_CODEC_ERROR;
1771 
1772     img =
1773 	gg_strip_image_create (in, GGRAPH_IMAGE_DEM_HDR, GG_PIXEL_GRID, width,
1774 			       height, bits_per_sample, 1, sample, NULL, NULL);
1775     if (!img)
1776       {
1777 	  ret = GGRAPH_INSUFFICIENT_MEMORY;
1778 	  goto error;
1779       }
1780 
1781 /* setting up georeferencing infos */
1782     img->is_georeferenced = 1;
1783     img->upper_left_x = ulx;
1784     img->upper_left_y = uly;
1785     img->pixel_x_size = pixel_x_size;
1786     img->pixel_y_size = pixel_y_size;
1787     img->no_data_value = no_data;
1788 
1789 /* setting up the GRID codec struct */
1790     grid_codec = malloc (sizeof (struct grid_codec_data));
1791     if (!grid_codec)
1792 	goto error;
1793     grid_codec->grid_type = GRID_DEM_HDR;
1794     grid_codec->is_writer = 0;
1795     grid_codec->grid_buffer = NULL;
1796     grid_codec->row_offsets = NULL;
1797     grid_codec->little_endian = endian;
1798     img->codec_data = grid_codec;
1799 
1800 /* allocating the GRID read buffer */
1801     if (bits_per_sample == 16)
1802 	buf_size = sizeof (short) * width;
1803     if (bits_per_sample == 32)
1804 	buf_size = sizeof (int) * width;
1805     grid_buffer = malloc (buf_size);
1806     if (!grid_buffer)
1807 	goto error;
1808     grid_codec->grid_buffer = grid_buffer;
1809 
1810     *image_handle = img;
1811     return GGRAPH_OK;
1812 
1813   error:
1814     if (img)
1815 	gGraphDestroyImage (img);
1816     return ret;
1817 }
1818 
1819 static int
parse_asc_offsets(FILE * in,int height,long ** row_offsets)1820 parse_asc_offsets (FILE * in, int height, long **row_offsets)
1821 {
1822 /* retrieving row-offsets from an ASC file [ASCII GRID format] */
1823     int c;
1824     int row = 0;
1825     int ind = 0;
1826     long *offsets = *row_offsets;
1827     long current = 0;
1828 
1829     rewind (in);
1830     while ((c = getc (in)) != EOF)
1831       {
1832 	  /* parsing the Header file */
1833 	  if (c == '\n')
1834 	    {
1835 		row++;
1836 		if (row >= 6)
1837 		  {
1838 		      if (ind < height)
1839 			  *(offsets + ind) = current;
1840 		      ind++;
1841 		  }
1842 	    }
1843 	  current++;
1844       }
1845     if (ind != height + 1)
1846 	return 0;
1847     return 1;
1848 }
1849 
1850 GGRAPH_PRIVATE int
gg_image_strip_prepare_from_ascii_grid(FILE * in,gGraphStripImagePtr * image_handle)1851 gg_image_strip_prepare_from_ascii_grid (FILE * in,
1852 					gGraphStripImagePtr * image_handle)
1853 {
1854 /* preparing to decode an ASCII-GRID [by strips] */
1855     gGraphStripImagePtr img = NULL;
1856     struct grid_codec_data *grid_codec = NULL;
1857     int width;
1858     int height;
1859     double ulx;
1860     double uly;
1861     double pixel_x_size;
1862     double pixel_y_size;
1863     double no_data;
1864     long *row_offsets = NULL;
1865     int ret = GGRAPH_ASCII_CODEC_ERROR;
1866     *image_handle = NULL;
1867 
1868     if (!parse_asc_hdr
1869 	(NULL, in, &width, &height, &ulx, &uly, &pixel_x_size, &pixel_y_size,
1870 	 &no_data))
1871 	return GGRAPH_ASCII_CODEC_ERROR;
1872 
1873 /* preparing the row-offset array */
1874     row_offsets = malloc (sizeof (long) * height);
1875     if (!row_offsets)
1876 	return GGRAPH_ASCII_CODEC_ERROR;
1877     if (!parse_asc_offsets (in, height, &row_offsets))
1878       {
1879 	  free (row_offsets);
1880 	  return GGRAPH_ASCII_CODEC_ERROR;
1881       }
1882 
1883     img =
1884 	gg_strip_image_create (in, GGRAPH_IMAGE_ASCII_GRID, GG_PIXEL_GRID,
1885 			       width, height, 32, 1, GGRAPH_SAMPLE_FLOAT, NULL,
1886 			       NULL);
1887     if (!img)
1888       {
1889 	  ret = GGRAPH_INSUFFICIENT_MEMORY;
1890 	  goto error;
1891       }
1892 
1893 /* setting up georeferencing infos */
1894     img->is_georeferenced = 1;
1895     img->upper_left_x = ulx;
1896     img->upper_left_y = uly;
1897     img->pixel_x_size = pixel_x_size;
1898     img->pixel_y_size = pixel_y_size;
1899     img->no_data_value = no_data;
1900 
1901 /* setting up the GRID codec struct */
1902     grid_codec = malloc (sizeof (struct grid_codec_data));
1903     if (!grid_codec)
1904 	goto error;
1905     grid_codec->grid_type = GRID_ASCII;
1906     grid_codec->is_writer = 0;
1907     grid_codec->grid_buffer = NULL;
1908     grid_codec->row_offsets = row_offsets;
1909     img->codec_data = grid_codec;
1910 
1911     *image_handle = img;
1912     return GGRAPH_OK;
1913 
1914   error:
1915     if (img)
1916 	gGraphDestroyImage (img);
1917     return ret;
1918 }
1919 
1920 static int
read_from_bin_grid(FILE * in,gGraphStripImagePtr img,int sample,int bits_per_pixel,int type,void * scanline,int endian)1921 read_from_bin_grid (FILE * in, gGraphStripImagePtr img, int sample,
1922 		    int bits_per_pixel, int type, void *scanline, int endian)
1923 {
1924 /* decoding a BIN-GRID or a FLT-GRID [by strip] */
1925     int width = img->width;
1926     int height = img->height;
1927     size_t scan_size;
1928     int row;
1929     int incr = 0;
1930     int x;
1931     int endian_arch = gg_endian_arch ();
1932     off_t pos;
1933     unsigned char *p_in;
1934     short *p_out_short;
1935     short cell_value_short;
1936     int *p_out_int;
1937     int cell_value_int;
1938     float *p_out_float;
1939     float cell_value_float;
1940     double *p_out_double;
1941     double cell_value_double;
1942 
1943     if (bits_per_pixel == 16)
1944 	scan_size = width * 2;
1945     if (bits_per_pixel == 32)
1946 	scan_size = width * 4;
1947     if (bits_per_pixel == 64)
1948 	scan_size = width * 8;
1949     pos = img->next_row * scan_size;
1950 /* positioning on the start scanline */
1951     if (fseek (in, pos, SEEK_SET) != 0)
1952       {
1953 	  if (type == GRID_BIN_HDR)
1954 	      return GGRAPH_BIN_CODEC_ERROR;
1955 	  if (type == GRID_FLT_HDR)
1956 	      return GGRAPH_FLT_CODEC_ERROR;
1957 	  if (type == GRID_DEM_HDR)
1958 	      return GGRAPH_DEM_CODEC_ERROR;
1959       }
1960     for (row = 0; row < img->rows_per_block; row++)
1961       {
1962 	  /* reading the required number of scanlines */
1963 	  if ((row + img->next_row) >= height)
1964 	      break;
1965 	  if (fread (scanline, 1, scan_size, in) != scan_size)
1966 	      return GGRAPH_HGT_CODEC_ERROR;
1967 	  p_in = scanline;
1968 	  if (sample == GGRAPH_SAMPLE_INT)
1969 	    {
1970 		if (bits_per_pixel == 16)
1971 		  {
1972 		      p_out_short = (short *) (img->pixels);
1973 		      p_out_short += (row * width);
1974 		  }
1975 
1976 		if (bits_per_pixel == 32)
1977 		  {
1978 		      p_out_int = (int *) (img->pixels);
1979 		      p_out_int += (row * width);
1980 		  }
1981 	    }
1982 	  if (sample == GGRAPH_SAMPLE_FLOAT)
1983 	    {
1984 		if (bits_per_pixel == 32)
1985 		  {
1986 		      p_out_float = (float *) (img->pixels);
1987 		      p_out_float += (row * width);
1988 		  }
1989 
1990 		if (bits_per_pixel == 64)
1991 		  {
1992 		      p_out_double = (double *) (img->pixels);
1993 		      p_out_double += (row * width);
1994 		  }
1995 	    }
1996 	  for (x = 0; x < width; x++)
1997 	    {
1998 		if (sample == GGRAPH_SAMPLE_INT)
1999 		  {
2000 		      if (bits_per_pixel == 16)
2001 			{
2002 			    cell_value_short =
2003 				gg_import_int16 (p_in, endian, endian_arch);
2004 			    *p_out_short++ = cell_value_short;
2005 			    p_in += sizeof (short);
2006 			}
2007 		      if (bits_per_pixel == 32)
2008 			{
2009 			    cell_value_int =
2010 				gg_import_int32 (p_in, endian, endian_arch);
2011 			    *p_out_int++ = cell_value_int;
2012 			    p_in += sizeof (int);
2013 			}
2014 		  }
2015 		if (sample == GGRAPH_SAMPLE_FLOAT)
2016 		  {
2017 		      if (bits_per_pixel == 32)
2018 			{
2019 			    cell_value_float =
2020 				gg_import_float (p_in, endian, endian_arch);
2021 			    *p_out_float++ = cell_value_float;
2022 			    p_in += sizeof (float);
2023 			}
2024 		      if (bits_per_pixel == 64)
2025 			{
2026 			    cell_value_double =
2027 				gg_import_double (p_in, endian, endian_arch);
2028 			    *p_out_double++ = cell_value_double;
2029 			    p_in += sizeof (double);
2030 			}
2031 		  }
2032 	    }
2033 	  incr++;
2034       }
2035     img->next_row += incr;
2036     img->current_available_rows = incr;
2037     return GGRAPH_OK;
2038 }
2039 
2040 GGRAPH_PRIVATE int
gg_image_strip_read_from_bin_grid(gGraphStripImagePtr img,int * progress)2041 gg_image_strip_read_from_bin_grid (gGraphStripImagePtr img, int *progress)
2042 {
2043 /* decoding a BIN-GRID or a FLT-GRID [by strip] */
2044     struct grid_codec_data *grid_codec =
2045 	(struct grid_codec_data *) (img->codec_data);
2046     FILE *in = img->file_handle;
2047 
2048     if (grid_codec->grid_type == GRID_BIN_HDR
2049 	|| grid_codec->grid_type == GRID_FLT_HDR)
2050       {
2051 	  int ret = read_from_bin_grid (in, img, img->sample_format,
2052 					img->bits_per_sample,
2053 					grid_codec->grid_type,
2054 					grid_codec->grid_buffer,
2055 					grid_codec->little_endian);
2056 	  if (ret == GGRAPH_OK && progress != NULL)
2057 	      *progress =
2058 		  (int) (((double) (img->next_row + 1) * 100.0) /
2059 			 (double) (img->height));
2060 	  return ret;
2061       }
2062     return GGRAPH_ERROR;
2063 }
2064 
2065 GGRAPH_PRIVATE int
gg_image_strip_read_from_dem_grid(gGraphStripImagePtr img,int * progress)2066 gg_image_strip_read_from_dem_grid (gGraphStripImagePtr img, int *progress)
2067 {
2068 /* decoding a DEM-GRID [by strip] */
2069     struct grid_codec_data *grid_codec =
2070 	(struct grid_codec_data *) (img->codec_data);
2071     FILE *in = img->file_handle;
2072 
2073     if (grid_codec->grid_type == GRID_DEM_HDR)
2074       {
2075 	  int ret = read_from_bin_grid (in, img, img->sample_format,
2076 					img->bits_per_sample,
2077 					grid_codec->grid_type,
2078 					grid_codec->grid_buffer,
2079 					grid_codec->little_endian);
2080 	  if (ret == GGRAPH_OK && progress != NULL)
2081 	      *progress =
2082 		  (int) (((double) (img->next_row + 1) * 100.0) /
2083 			 (double) (img->height));
2084 	  return ret;
2085       }
2086     return GGRAPH_ERROR;
2087 }
2088 
2089 static int
read_from_ascii_grid(FILE * in,gGraphStripImagePtr img,long * row_offsets)2090 read_from_ascii_grid (FILE * in, gGraphStripImagePtr img, long *row_offsets)
2091 {
2092 /* decoding an ASCII-GRID [by strip] */
2093     int width = img->width;
2094     int height = img->height;
2095     int row;
2096     int incr = 0;
2097     int col;
2098     int c;
2099     float *p_out;
2100     float cell_value;
2101     char buf[256];
2102     char *p;
2103 
2104 /* positioning on the start scanline */
2105     if (fseek (in, row_offsets[img->next_row], SEEK_SET) != 0)
2106 	return GGRAPH_ASCII_CODEC_ERROR;
2107     if (getc (in) != '\n')
2108 	return GGRAPH_ASCII_CODEC_ERROR;
2109 
2110     for (row = 0; row < img->rows_per_block; row++)
2111       {
2112 	  /* reading the required number of scanlines */
2113 	  if ((row + img->next_row) >= height)
2114 	      break;
2115 	  p_out = (float *) (img->pixels);
2116 	  p_out += row * width;
2117 	  p = buf;
2118 	  col = 0;
2119 	  while ((c = getc (in)) != EOF)
2120 	    {
2121 		/* parsing cell values */
2122 		if (c == '\r')
2123 		    continue;
2124 		if (c == '\n')
2125 		    break;
2126 		if (c == ' ')
2127 		  {
2128 		      /* cell end */
2129 		      *p = '\0';
2130 		      cell_value = atof (buf);
2131 		      if (col >= width)
2132 			  return GGRAPH_ASCII_CODEC_ERROR;
2133 		      *p_out++ = cell_value;
2134 		      col++;
2135 		      p = buf;
2136 		      continue;
2137 		  }
2138 		if ((p - buf) >= 256)
2139 		    return GGRAPH_ASCII_CODEC_ERROR;
2140 		*p++ = c;
2141 	    }
2142 	  if (col != width)
2143 	      return GGRAPH_ASCII_CODEC_ERROR;
2144 	  incr++;
2145       }
2146     img->next_row += incr;
2147     img->current_available_rows = incr;
2148     return GGRAPH_OK;
2149 }
2150 
2151 GGRAPH_PRIVATE int
gg_image_strip_read_from_ascii_grid(gGraphStripImagePtr img,int * progress)2152 gg_image_strip_read_from_ascii_grid (gGraphStripImagePtr img, int *progress)
2153 {
2154 /* decoding an ASCII-GRID [by strip] */
2155     struct grid_codec_data *grid_codec =
2156 	(struct grid_codec_data *) (img->codec_data);
2157     FILE *in = img->file_handle;
2158 
2159     if (grid_codec->grid_type == GRID_ASCII)
2160       {
2161 	  int ret = read_from_ascii_grid (in, img, grid_codec->row_offsets);
2162 	  if (ret == GGRAPH_OK && progress != NULL)
2163 	      *progress =
2164 		  (int) (((double) (img->next_row + 1) * 100.0) /
2165 			 (double) (img->height));
2166 	  return ret;
2167       }
2168     return GGRAPH_ERROR;
2169 }
2170 
2171 GGRAPH_PRIVATE int
gg_image_prepare_to_ascii_grid_by_strip(const gGraphStripImagePtr img,FILE * out)2172 gg_image_prepare_to_ascii_grid_by_strip (const gGraphStripImagePtr img,
2173 					 FILE * out)
2174 {
2175 /* preparing to export an ASCII GRID [by strips] */
2176     char dummy[256];
2177 
2178     fprintf (out, "ncols        %d\r\n", img->width);
2179     fprintf (out, "nrows        %d\r\n", img->height);
2180     gGraphSmartPrintf (img->upper_left_x, dummy);
2181     fprintf (out, "xllcorner    %s\r\n", dummy);
2182     gGraphSmartPrintf (img->upper_left_y -
2183 		       ((double) (img->height) * img->pixel_y_size), dummy);
2184     fprintf (out, "yllcorner    %s\r\n", dummy);
2185     gGraphSmartPrintf (img->pixel_y_size, dummy);
2186     fprintf (out, "cellsize     %s\r\n", dummy);
2187     gGraphSmartPrintf (img->no_data_value, dummy);
2188     fprintf (out, "NODATA_value %s\r\n", dummy);
2189 
2190     return GGRAPH_OK;
2191 }
2192 
2193 GGRAPH_PRIVATE int
gg_image_write_to_ascii_grid_by_strip(const gGraphStripImagePtr img,int * progress)2194 gg_image_write_to_ascii_grid_by_strip (const gGraphStripImagePtr img,
2195 				       int *progress)
2196 {
2197 /* scanline(s) ASCII GRID export [by strip] */
2198     FILE *out = img->file_handle;
2199     int row;
2200     int col;
2201     char *p_in_int8;
2202     unsigned char *p_in_uint8;
2203     short *p_in_int16;
2204     unsigned short *p_in_uint16;
2205     int *p_in_int32;
2206     unsigned int *p_in_uint32;
2207     float *p_in_flt;
2208     double *p_in_dbl;
2209     char dummy[256];
2210 
2211     for (row = 0; row < img->current_available_rows; row++)
2212       {
2213 	  switch (img->sample_format)
2214 	    {
2215 	    case GGRAPH_SAMPLE_UINT:
2216 		switch (img->bits_per_sample)
2217 		  {
2218 		  case 8:
2219 		      p_in_uint8 = (unsigned char *) (img->pixels);
2220 		      p_in_uint8 += row * img->width;
2221 		      break;
2222 		  case 16:
2223 		      p_in_uint16 = (unsigned short *) (img->pixels);
2224 		      p_in_uint16 += row * img->width;
2225 		      break;
2226 		  case 32:
2227 		      p_in_uint32 = (unsigned int *) (img->pixels);
2228 		      p_in_uint32 += row * img->width;
2229 		      break;
2230 		  };
2231 		break;
2232 	    case GGRAPH_SAMPLE_INT:
2233 		switch (img->bits_per_sample)
2234 		  {
2235 		  case 8:
2236 		      p_in_int8 = (char *) (img->pixels);
2237 		      p_in_int8 += row * img->width;
2238 		      break;
2239 		  case 16:
2240 		      p_in_int16 = (short *) (img->pixels);
2241 		      p_in_int16 += row * img->width;
2242 		      break;
2243 		  case 32:
2244 		      p_in_int32 = (int *) (img->pixels);
2245 		      p_in_int32 += row * img->width;
2246 		      break;
2247 		  };
2248 		break;
2249 	    case GGRAPH_SAMPLE_FLOAT:
2250 		switch (img->bits_per_sample)
2251 		  {
2252 		  case 32:
2253 		      p_in_flt = (float *) (img->pixels);
2254 		      p_in_flt += row * img->width;
2255 		      break;
2256 		  case 64:
2257 		      p_in_dbl = (double *) (img->pixels);
2258 		      p_in_dbl += row * img->width;
2259 		      break;
2260 		  };
2261 		break;
2262 	    };
2263 	  for (col = 0; col < img->width; col++)
2264 	    {
2265 		switch (img->sample_format)
2266 		  {
2267 		  case GGRAPH_SAMPLE_UINT:
2268 		      switch (img->bits_per_sample)
2269 			{
2270 			case 8:
2271 			    sprintf (dummy, "%u", *p_in_uint8++);
2272 			    break;
2273 			case 16:
2274 			    sprintf (dummy, "%u", *p_in_uint16++);
2275 			    break;
2276 			case 32:
2277 			    sprintf (dummy, "%u", *p_in_uint32++);
2278 			    break;
2279 			};
2280 		      break;
2281 		  case GGRAPH_SAMPLE_INT:
2282 		      switch (img->bits_per_sample)
2283 			{
2284 			case 8:
2285 			    sprintf (dummy, "%d", *p_in_int8++);
2286 			    break;
2287 			case 16:
2288 			    sprintf (dummy, "%d", *p_in_int16++);
2289 			    break;
2290 			case 32:
2291 			    sprintf (dummy, "%d", *p_in_int32++);
2292 			    break;
2293 			};
2294 		      break;
2295 		  case GGRAPH_SAMPLE_FLOAT:
2296 		      switch (img->bits_per_sample)
2297 			{
2298 			case 32:
2299 			    gGraphSmartPrintf (*p_in_flt++, dummy);
2300 			    break;
2301 			case 64:
2302 			    gGraphSmartPrintf (*p_in_dbl++, dummy);
2303 			    break;
2304 			};
2305 		      break;
2306 		  };
2307 		fprintf (out, "%s ", dummy);
2308 	    }
2309 	  /* terminating a full scanline */
2310 	  fprintf (out, "\r\n");
2311       }
2312     img->next_row += img->current_available_rows;
2313 
2314     if (progress != NULL)
2315 	*progress =
2316 	    (int) (((double) (img->next_row + 1) * 100.0) /
2317 		   (double) (img->height));
2318     return GGRAPH_OK;
2319 }
2320 
2321 GGRAPH_PRIVATE int
gg_image_prepare_to_bin_hdr_by_strip(const gGraphStripImagePtr img)2322 gg_image_prepare_to_bin_hdr_by_strip (const gGraphStripImagePtr img)
2323 {
2324 /* preparing to export a BIN+HDR GRID [by strips] */
2325     struct grid_codec_data *grid_codec = NULL;
2326     int buf_size;
2327     void *grid_buffer = NULL;
2328 
2329     if (img->sample_format != GGRAPH_SAMPLE_INT)
2330 	return GGRAPH_BIN_CODEC_ERROR;
2331     if (img->bits_per_sample == 16 || img->bits_per_sample == 32)
2332 	;
2333     else
2334 	return GGRAPH_BIN_CODEC_ERROR;
2335 
2336 /* setting up the GRID codec struct */
2337     grid_codec = malloc (sizeof (struct grid_codec_data));
2338     if (!grid_codec)
2339 	return GGRAPH_BIN_CODEC_ERROR;
2340     grid_codec->grid_type = GRID_BIN_HDR;
2341     grid_codec->is_writer = 1;
2342     grid_codec->grid_buffer = NULL;
2343     grid_codec->row_offsets = NULL;
2344 
2345 /* allocating the GRID read buffer */
2346     if (img->bits_per_sample == 16)
2347 	buf_size = sizeof (short) * img->width;
2348     else
2349 	buf_size = sizeof (int) * img->width;
2350     grid_buffer = malloc (buf_size);
2351     if (!grid_buffer)
2352       {
2353 	  free (grid_codec);
2354 	  return GGRAPH_BIN_CODEC_ERROR;
2355       }
2356     grid_codec->grid_buffer = grid_buffer;
2357     img->codec_data = grid_codec;
2358 
2359     return GGRAPH_OK;
2360 }
2361 
2362 GGRAPH_PRIVATE int
gg_image_prepare_to_flt_hdr_by_strip(const gGraphStripImagePtr img)2363 gg_image_prepare_to_flt_hdr_by_strip (const gGraphStripImagePtr img)
2364 {
2365 /* preparing to export a FLT+HDR GRID [by strips] */
2366     struct grid_codec_data *grid_codec = NULL;
2367     int buf_size;
2368     void *grid_buffer = NULL;
2369 
2370     if (img->sample_format != GGRAPH_SAMPLE_FLOAT)
2371 	return GGRAPH_FLT_CODEC_ERROR;
2372     if (img->bits_per_sample == 32 || img->bits_per_sample == 64)
2373 	;
2374     else
2375 	return GGRAPH_FLT_CODEC_ERROR;
2376 
2377 /* setting up the GRID codec struct */
2378     grid_codec = malloc (sizeof (struct grid_codec_data));
2379     if (!grid_codec)
2380 	return GGRAPH_FLT_CODEC_ERROR;
2381     grid_codec->grid_type = GRID_FLT_HDR;
2382     grid_codec->is_writer = 1;
2383     grid_codec->grid_buffer = NULL;
2384     grid_codec->row_offsets = NULL;
2385 
2386 /* allocating the GRID read buffer */
2387     if (img->bits_per_sample == 32)
2388 	buf_size = sizeof (float) * img->width;
2389     else
2390 	buf_size = sizeof (double) * img->width;
2391     grid_buffer = malloc (buf_size);
2392     if (!grid_buffer)
2393       {
2394 	  free (grid_codec);
2395 	  return GGRAPH_FLT_CODEC_ERROR;
2396       }
2397     grid_codec->grid_buffer = grid_buffer;
2398     img->codec_data = grid_codec;
2399 
2400     return GGRAPH_OK;
2401 }
2402 
2403 GGRAPH_PRIVATE int
gg_image_write_to_bin_hdr_by_strip(const gGraphStripImagePtr img,int * progress)2404 gg_image_write_to_bin_hdr_by_strip (const gGraphStripImagePtr img,
2405 				    int *progress)
2406 {
2407 /* scanline(s) BIN+HDR GRID export [by strip] */
2408     FILE *out = img->file_handle;
2409     struct grid_codec_data *grid_codec =
2410 	(struct grid_codec_data *) (img->codec_data);
2411     int row;
2412     int col;
2413     short *p_in_int16;
2414     int *p_in_int32;
2415     unsigned char *p_out;
2416     size_t sz;
2417     int endian_arch = gg_endian_arch ();
2418 
2419     for (row = 0; row < img->current_available_rows; row++)
2420       {
2421 	  switch (img->bits_per_sample)
2422 	    {
2423 	    case 16:
2424 		p_in_int16 = (short *) (img->pixels);
2425 		p_in_int16 += row * img->width;
2426 		sz = img->width * sizeof (short);
2427 		break;
2428 	    case 32:
2429 		p_in_int32 = (int *) (img->pixels);
2430 		p_in_int32 += row * img->width;
2431 		sz = img->width * sizeof (int);
2432 		break;
2433 	    };
2434 	  p_out = grid_codec->grid_buffer;
2435 
2436 	  for (col = 0; col < img->width; col++)
2437 	    {
2438 		switch (img->bits_per_sample)
2439 		  {
2440 		  case 16:
2441 		      if (*p_in_int16 < img->min_value)
2442 			  img->min_value = *p_in_int16;
2443 		      if (*p_in_int16 > img->max_value)
2444 			  img->max_value = *p_in_int16;
2445 		      gg_export_int16 (*p_in_int16++, p_out, 1, endian_arch);
2446 		      p_out += sizeof (short);
2447 		      break;
2448 		  case 32:
2449 		      if (*p_in_int32 < img->min_value)
2450 			  img->min_value = *p_in_int32;
2451 		      if (*p_in_int32 > img->max_value)
2452 			  img->max_value = *p_in_int32;
2453 		      gg_export_int32 (*p_in_int32++, p_out, 1, endian_arch);
2454 		      p_out += sizeof (int);
2455 		      break;
2456 		  };
2457 	    }
2458 	  /* terminating a full scanline */
2459 	  if (fwrite (grid_codec->grid_buffer, 1, sz, out) != sz)
2460 	      return GGRAPH_BIN_CODEC_ERROR;
2461       }
2462     img->next_row += img->current_available_rows;
2463 
2464     if (progress != NULL)
2465 	*progress =
2466 	    (int) (((double) (img->next_row + 1) * 100.0) /
2467 		   (double) (img->height));
2468     return GGRAPH_OK;
2469 }
2470 
2471 GGRAPH_PRIVATE int
gg_image_write_to_flt_hdr_by_strip(const gGraphStripImagePtr img,int * progress)2472 gg_image_write_to_flt_hdr_by_strip (const gGraphStripImagePtr img,
2473 				    int *progress)
2474 {
2475 /* scanline(s) FLT+HDR GRID export [by strip] */
2476     FILE *out = img->file_handle;
2477     struct grid_codec_data *grid_codec =
2478 	(struct grid_codec_data *) (img->codec_data);
2479     int row;
2480     int col;
2481     float *p_in_float;
2482     double *p_in_double;
2483     unsigned char *p_out;
2484     size_t sz;
2485     int endian_arch = gg_endian_arch ();
2486 
2487     for (row = 0; row < img->current_available_rows; row++)
2488       {
2489 	  switch (img->bits_per_sample)
2490 	    {
2491 	    case 32:
2492 		p_in_float = (float *) (img->pixels);
2493 		p_in_float += row * img->width;
2494 		sz = img->width * sizeof (float);
2495 		break;
2496 	    case 64:
2497 		p_in_double = (double *) (img->pixels);
2498 		p_in_double += row * img->width;
2499 		sz = img->width * sizeof (double);
2500 		break;
2501 	    };
2502 	  p_out = grid_codec->grid_buffer;
2503 
2504 	  for (col = 0; col < img->width; col++)
2505 	    {
2506 		switch (img->bits_per_sample)
2507 		  {
2508 		  case 32:
2509 		      if (*p_in_float < img->min_value)
2510 			  img->min_value = *p_in_float;
2511 		      if (*p_in_float > img->max_value)
2512 			  img->max_value = *p_in_float;
2513 		      gg_export_float (*p_in_float++, p_out, 1, endian_arch);
2514 		      p_out += sizeof (float);
2515 		      break;
2516 		  case 64:
2517 		      if (*p_in_double < img->min_value)
2518 			  img->min_value = *p_in_double;
2519 		      if (*p_in_double > img->max_value)
2520 			  img->max_value = *p_in_double;
2521 		      gg_export_double (*p_in_double++, p_out, 1, endian_arch);
2522 		      p_out += sizeof (float);
2523 		      break;
2524 		  };
2525 	    }
2526 	  /* terminating a full scanline */
2527 	  if (fwrite (grid_codec->grid_buffer, 1, sz, out) != sz)
2528 	      return GGRAPH_FLT_CODEC_ERROR;
2529       }
2530     img->next_row += img->current_available_rows;
2531 
2532     if (progress != NULL)
2533 	*progress =
2534 	    (int) (((double) (img->next_row + 1) * 100.0) /
2535 		   (double) (img->height));
2536     return GGRAPH_OK;
2537 }
2538 
2539 GGRAPH_DECLARE int
gGraphWriteBinHeader(const char * hdr_path,const void * ptr)2540 gGraphWriteBinHeader (const char *hdr_path, const void *ptr)
2541 {
2542 /* exporting a BIN Header file */
2543     FILE *out = NULL;
2544     char dummy[256];
2545     gGraphStripImagePtr img = (gGraphStripImagePtr) ptr;
2546 
2547     if (img == NULL)
2548 	return GGRAPH_INVALID_IMAGE;
2549     if (img->signature != GG_STRIP_IMAGE_MAGIC_SIGNATURE)
2550 	return GGRAPH_INVALID_IMAGE;
2551 
2552 /* attempting to open/create the header file */
2553     out = fopen (hdr_path, "wb");
2554     if (out == NULL)
2555 	return GGRAPH_FILE_OPEN_ERROR;
2556 
2557     fprintf (out, "NCOLS         %d\r\n", img->width);
2558     fprintf (out, "NROWS         %d\r\n", img->height);
2559     gGraphSmartPrintf (img->upper_left_x, dummy);
2560     fprintf (out, "XLLCORNER     %s\r\n", dummy);
2561     gGraphSmartPrintf (img->upper_left_y -
2562 		       ((double) (img->height) * img->pixel_y_size), dummy);
2563     fprintf (out, "YLLCORNER     %s\r\n", dummy);
2564     gGraphSmartPrintf (img->pixel_y_size, dummy);
2565     fprintf (out, "CELLSIZE      %s\r\n", dummy);
2566     gGraphSmartPrintf (img->no_data_value, dummy);
2567     fprintf (out, "NODATA_VALUE  %s\r\n", dummy);
2568     fprintf (out, "BYTEORDER     LSBFIRST\r\n");
2569     if (img->bits_per_sample == 16)
2570 	fprintf (out, "NUMBERTYPE    2_BYTE_INTEGER\r\n");
2571     else
2572 	fprintf (out, "NUMBERTYPE    4_BYTE_INTEGER\r\n");
2573     fprintf (out, "ZUNITS        METERS\r\n");
2574     gGraphSmartPrintf (img->min_value, dummy);
2575     fprintf (out, "MIN_VALUE     %s\r\n", dummy);
2576     gGraphSmartPrintf (img->max_value, dummy);
2577     fprintf (out, "MAX_VALUE     %s\r\n", dummy);
2578 
2579     fclose (out);
2580 
2581     return GGRAPH_OK;
2582 }
2583 
2584 GGRAPH_DECLARE int
gGraphWriteFltHeader(const char * hdr_path,const void * ptr)2585 gGraphWriteFltHeader (const char *hdr_path, const void *ptr)
2586 {
2587 /* exporting a FLT Header file */
2588     FILE *out = NULL;
2589     char dummy[256];
2590     gGraphStripImagePtr img = (gGraphStripImagePtr) ptr;
2591 
2592     if (img == NULL)
2593 	return GGRAPH_INVALID_IMAGE;
2594     if (img->signature != GG_STRIP_IMAGE_MAGIC_SIGNATURE)
2595 	return GGRAPH_INVALID_IMAGE;
2596 
2597 /* attempting to open/create the header file */
2598     out = fopen (hdr_path, "wb");
2599     if (out == NULL)
2600 	return GGRAPH_FILE_OPEN_ERROR;
2601 
2602     fprintf (out, "ncols         %d\r\n", img->width);
2603     fprintf (out, "nrows         %d\r\n", img->height);
2604     gGraphSmartPrintf (img->upper_left_x, dummy);
2605     fprintf (out, "xllcorner     %s\r\n", dummy);
2606     gGraphSmartPrintf (img->upper_left_y -
2607 		       ((double) (img->height) * img->pixel_y_size), dummy);
2608     fprintf (out, "yllcorner     %s\r\n", dummy);
2609     gGraphSmartPrintf (img->pixel_y_size, dummy);
2610     fprintf (out, "cellsize      %s\r\n", dummy);
2611     gGraphSmartPrintf (img->no_data_value, dummy);
2612     fprintf (out, "NODATA_value  %s\r\n", dummy);
2613     fprintf (out, "byteorder     LSBFIRST\r\n");
2614     if (img->bits_per_sample == 32)
2615 	fprintf (out, "NUMBERTYPE    4_BYTE_FLOAT\r\n");
2616     else
2617 	fprintf (out, "NUMBERTYPE    8_BYTE_FLOAT\r\n");
2618     gGraphSmartPrintf (img->min_value, dummy);
2619     fprintf (out, "MIN_VALUE     %s\r\n", dummy);
2620     gGraphSmartPrintf (img->max_value, dummy);
2621     fprintf (out, "MAX_VALUE     %s\r\n", dummy);
2622 
2623     fclose (out);
2624 
2625     return GGRAPH_OK;
2626 }
2627