1 /*
2 
3  rl2ascii -- ASCII Grids related functions
4 
5  version 0.1, 2013 December 26
6 
7  Author: Sandro Furieri a.furieri@lqt.it
8 
9  -----------------------------------------------------------------------------
10 
11  Version: MPL 1.1/GPL 2.0/LGPL 2.1
12 
13  The contents of this file are subject to the Mozilla Public License Version
14  1.1 (the "License"); you may not use this file except in compliance with
15  the License. You may obtain a copy of the License at
16  http://www.mozilla.org/MPL/
17 
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22 
23 The Original Code is the SpatiaLite library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2008-2013
28 the Initial Developer. All Rights Reserved.
29 
30 Alternatively, the contents of this file may be used under the terms of
31 either the GNU General Public License Version 2 or later (the "GPL"), or
32 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 in which case the provisions of the GPL or the LGPL are applicable instead
34 of those above. If you wish to allow use of your version of this file only
35 under the terms of either the GPL or the LGPL, and not to allow others to
36 use your version of this file under the terms of the MPL, indicate your
37 decision by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL or the LGPL. If you do not delete
39 the provisions above, a recipient may use your version of this file under
40 the terms of any one of the MPL, the GPL or the LGPL.
41 
42 */
43 
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <float.h>
48 
49 #include "rasterlite2/sqlite.h"
50 
51 #include "config.h"
52 
53 #include "rasterlite2/rasterlite2.h"
54 #include "rasterlite2/rl2tiff.h"
55 #include "rasterlite2_private.h"
56 
57 static int
parse_ncols(const char * str,unsigned int * width)58 parse_ncols (const char *str, unsigned int *width)
59 {
60 /* attempting to parse the NCOLS item */
61     if (strncasecmp (str, "ncols ", 6) == 0)
62       {
63 	  *width = atoi (str + 6);
64 	  return 1;
65       }
66     return 0;
67 }
68 
69 static int
parse_nrows(const char * str,unsigned int * height)70 parse_nrows (const char *str, unsigned int *height)
71 {
72 /* attempting to parse the NROWS item */
73     if (strncasecmp (str, "nrows ", 6) == 0)
74       {
75 	  *height = atoi (str + 6);
76 	  return 1;
77       }
78     return 0;
79 }
80 
81 static int
parse_xllcorner(const char * str,double * minx)82 parse_xllcorner (const char *str, double *minx)
83 {
84 /* attempting to parse the XLLCORNER item */
85     if (strncasecmp (str, "xllcorner ", 10) == 0)
86       {
87 	  *minx = atof (str + 10);
88 	  return 1;
89       }
90     return 0;
91 }
92 
93 static int
parse_yllcorner(const char * str,double * miny)94 parse_yllcorner (const char *str, double *miny)
95 {
96 /* attempting to parse the YLLCORNER item */
97     if (strncasecmp (str, "yllcorner ", 10) == 0)
98       {
99 	  *miny = atof (str + 10);
100 	  return 1;
101       }
102     return 0;
103 }
104 
105 static int
parse_xllcenter(const char * str,double * minx)106 parse_xllcenter (const char *str, double *minx)
107 {
108 /* attempting to parse the XLLCENTER item */
109     if (strncasecmp (str, "xllcenter ", 10) == 0)
110       {
111 	  *minx = atof (str + 10);
112 	  return 1;
113       }
114     return 0;
115 }
116 
117 static int
parse_yllcenter(const char * str,double * miny)118 parse_yllcenter (const char *str, double *miny)
119 {
120 /* attempting to parse the YLLCENTER item */
121     if (strncasecmp (str, "yllcenter ", 10) == 0)
122       {
123 	  *miny = atof (str + 10);
124 	  return 1;
125       }
126     return 0;
127 }
128 
129 static int
parse_cellsize(const char * str,double * xres)130 parse_cellsize (const char *str, double *xres)
131 {
132 /* attempting to parse the CELLSIZE item */
133     if (strncasecmp (str, "cellsize ", 9) == 0)
134       {
135 	  *xres = atof (str + 9);
136 	  return 1;
137       }
138     return 0;
139 }
140 
141 static int
parse_nodata(const char * str,double * no_data)142 parse_nodata (const char *str, double *no_data)
143 {
144 /* attempting to parse the NODATA_value item */
145     if (strncasecmp (str, "NODATA_value ", 13) == 0)
146       {
147 	  *no_data = atof (str + 13);
148 	  return 1;
149       }
150     return 0;
151 }
152 
153 static int
get_ascii_header(FILE * in,unsigned int * width,unsigned int * height,double * minx,double * miny,double * maxx,double * maxy,double * xres,double * yres,double * no_data)154 get_ascii_header (FILE * in, unsigned int *width, unsigned int *height,
155 		  double *minx, double *miny, double *maxx, double *maxy,
156 		  double *xres, double *yres, double *no_data)
157 {
158 /* attempting to parse the ASCII Header */
159     char buf[1024];
160     char *p_out = buf;
161     int line_no = 0;
162     int c;
163     int ok_ncols = 0;
164     int ok_nrows = 0;
165     int ok_xll = 0;
166     int ok_yll = 0;
167     int ok_cellsize = 0;
168     int ok_nodata = 0;
169 
170     while ((c = getc (in)) != EOF)
171       {
172 	  if (c == '\r')
173 	      continue;
174 	  if (c == '\n')
175 	    {
176 		*p_out = '\0';
177 		if (parse_ncols (buf, width))
178 		    ok_ncols++;
179 		if (parse_nrows (buf, height))
180 		    ok_nrows++;
181 		if (parse_xllcorner (buf, minx))
182 		    ok_xll++;
183 		if (parse_xllcenter (buf, minx))
184 		    ok_xll++;
185 		if (parse_yllcorner (buf, miny))
186 		    ok_yll++;
187 		if (parse_yllcenter (buf, miny))
188 		    ok_yll++;
189 		if (parse_cellsize (buf, xres))
190 		    ok_cellsize++;
191 		if (parse_nodata (buf, no_data))
192 		    ok_nodata++;
193 		line_no++;
194 		if (line_no == 6)
195 		    break;
196 		p_out = buf;
197 		continue;
198 	    }
199 	  if ((p_out - buf) >= 1024)
200 	      goto error;
201 	  *p_out++ = c;
202       }
203     if (ok_ncols == 1 && ok_nrows == 1 && ok_xll == 1 && ok_yll == 1
204 	&& ok_cellsize == 1 && ok_nodata == 1)
205 	;
206     else
207 	goto error;
208 
209     *maxx = *minx + ((double) (*width) * *xres);
210     *yres = *xres;
211     *maxy = *miny + ((double) (*height) * *yres);
212     return 1;
213 
214   error:
215     *width = 0;
216     *height = 0;
217     *minx = DBL_MAX;
218     *miny = DBL_MAX;
219     *maxx = 0.0 - DBL_MAX;
220     *maxy = 0.0 - DBL_MAX;
221     *xres = 0.0;
222     *yres = 0.0;
223     *no_data = DBL_MAX;
224     return 0;
225 }
226 
227 static rl2PrivAsciiOriginPtr
alloc_ascii_origin(const char * path,int srid,unsigned char sample_type,unsigned short width,unsigned short height,double minx,double miny,double maxx,double maxy,double xres,double yres,double no_data)228 alloc_ascii_origin (const char *path, int srid, unsigned char sample_type,
229 		    unsigned short width, unsigned short height, double minx,
230 		    double miny, double maxx, double maxy, double xres,
231 		    double yres, double no_data)
232 {
233 /* allocating and initializing an ASCII Grid origin */
234     int len;
235     rl2PrivAsciiOriginPtr ascii = malloc (sizeof (rl2PrivAsciiOrigin));
236     if (ascii == NULL)
237 	return NULL;
238     len = strlen (path);
239     ascii->path = malloc (len + 1);
240     strcpy (ascii->path, path);
241     ascii->tmp = NULL;
242     ascii->width = width;
243     ascii->height = height;
244     ascii->Srid = srid;
245     ascii->hResolution = xres;
246     ascii->vResolution = yres;
247     ascii->minX = minx;
248     ascii->minY = miny;
249     ascii->maxX = maxx;
250     ascii->maxY = maxy;
251     ascii->sample_type = sample_type;
252     ascii->noData = no_data;
253     return ascii;
254 }
255 
256 RL2_DECLARE rl2AsciiGridOriginPtr
rl2_create_ascii_grid_origin(const char * path,int srid,unsigned char sample_type)257 rl2_create_ascii_grid_origin (const char *path, int srid,
258 			      unsigned char sample_type)
259 {
260 /* creating an ASCII Grid Origin */
261     FILE *in;
262     unsigned int width;
263     unsigned int height;
264     double minx;
265     double miny;
266     double maxx;
267     double maxy;
268     double xres;
269     double yres;
270     double no_data;
271     char buf[1024];
272     char *p_out = buf;
273     unsigned int line_no = 0;
274     unsigned int col_no = 0;
275     int new_line = 1;
276     int c;
277     rl2PrivAsciiOriginPtr ascii = NULL;
278     void *scanline = NULL;
279     char *p_int8;
280     unsigned char *p_uint8;
281     short *p_int16;
282     unsigned short *p_uint16;
283     int *p_int32;
284     unsigned int *p_uint32;
285     float *p_float;
286     double *p_double;
287     int sz;
288 
289     if (path == NULL)
290 	return NULL;
291     if (srid <= 0)
292 	return NULL;
293     switch (sample_type)
294       {
295       case RL2_SAMPLE_INT8:
296       case RL2_SAMPLE_UINT8:
297       case RL2_SAMPLE_INT16:
298       case RL2_SAMPLE_UINT16:
299       case RL2_SAMPLE_INT32:
300       case RL2_SAMPLE_UINT32:
301       case RL2_SAMPLE_FLOAT:
302       case RL2_SAMPLE_DOUBLE:
303 	  break;
304       default:
305 	  return NULL;
306       };
307 
308     in = fopen (path, "r");
309     if (in == NULL)
310       {
311 	  fprintf (stderr, "ASCII Origin: Unable to open %s\n", path);
312 	  return NULL;
313       }
314     if (!get_ascii_header
315 	(in, &width, &height, &minx, &miny, &maxx, &maxy, &xres, &yres,
316 	 &no_data))
317       {
318 	  fprintf (stderr, "ASCII Origin: invalid Header found on %s\n", path);
319 	  goto error;
320       }
321 
322     ascii =
323 	alloc_ascii_origin (path, srid, sample_type, width, height, minx, miny,
324 			    maxx, maxy, xres, yres, no_data);
325     if (ascii == NULL)
326 	goto error;
327 
328     *buf = '\0';
329     col_no = width;
330 /* creating the helper Temporary File */
331     ascii->tmp = tmpfile ();
332     if (ascii->tmp == NULL)
333 	goto error;
334     switch (sample_type)
335       {
336       case RL2_SAMPLE_INT8:
337       case RL2_SAMPLE_UINT8:
338 	  sz = ascii->width;
339 	  break;
340       case RL2_SAMPLE_INT16:
341       case RL2_SAMPLE_UINT16:
342 	  sz = ascii->width * 2;
343 	  break;
344       case RL2_SAMPLE_INT32:
345       case RL2_SAMPLE_UINT32:
346       case RL2_SAMPLE_FLOAT:
347 	  sz = ascii->width * 4;
348 	  break;
349       case RL2_SAMPLE_DOUBLE:
350 	  sz = ascii->width * 8;
351 	  break;
352       };
353     scanline = malloc (sz);
354     if (scanline == NULL)
355 	goto error;
356 
357     while ((c = getc (in)) != EOF)
358       {
359 	  if (c == '\r')
360 	      continue;
361 	  if (c == ' ' || c == '\n')
362 	    {
363 		*p_out = '\0';
364 		if (*buf != '\0')
365 		  {
366 		      char int8_value;
367 		      unsigned char uint8_value;
368 		      short int16_value;
369 		      unsigned short uint16_value;
370 		      int int32_value;
371 		      unsigned int uint32_value;
372 		      float flt_value;
373 		      double dbl_value = atof (buf);
374 		      if (new_line)
375 			{
376 			    if (col_no != width)
377 				goto error;
378 			    line_no++;
379 			    new_line = 0;
380 			    col_no = 0;
381 			    switch (sample_type)
382 			      {
383 			      case RL2_SAMPLE_INT8:
384 				  p_int8 = scanline;
385 				  break;
386 			      case RL2_SAMPLE_UINT8:
387 				  p_uint8 = scanline;
388 				  break;
389 			      case RL2_SAMPLE_INT16:
390 				  p_int16 = scanline;
391 				  break;
392 			      case RL2_SAMPLE_UINT16:
393 				  p_uint16 = scanline;
394 				  break;
395 			      case RL2_SAMPLE_INT32:
396 				  p_int32 = scanline;
397 				  break;
398 			      case RL2_SAMPLE_UINT32:
399 				  p_uint32 = scanline;
400 				  break;
401 			      case RL2_SAMPLE_FLOAT:
402 				  p_float = scanline;
403 				  break;
404 			      case RL2_SAMPLE_DOUBLE:
405 				  p_double = scanline;
406 				  break;
407 			      };
408 			}
409 		      switch (sample_type)
410 			{
411 			case RL2_SAMPLE_INT8:
412 			    int8_value = truncate_8 (dbl_value);
413 			    *p_int8++ = int8_value;
414 			    break;
415 			case RL2_SAMPLE_UINT8:
416 			    uint8_value = truncate_u8 (dbl_value);
417 			    *p_uint8++ = uint8_value;
418 			    break;
419 			case RL2_SAMPLE_INT16:
420 			    int16_value = truncate_16 (dbl_value);
421 			    *p_int16++ = int16_value;
422 			    break;
423 			case RL2_SAMPLE_UINT16:
424 			    uint16_value = truncate_u16 (dbl_value);
425 			    *p_uint16++ = uint16_value;
426 			    break;
427 			case RL2_SAMPLE_INT32:
428 			    int32_value = truncate_32 (dbl_value);
429 			    *p_int32++ = int32_value;
430 			    break;
431 			case RL2_SAMPLE_UINT32:
432 			    uint32_value = truncate_u32 (dbl_value);
433 			    *p_uint32++ = uint32_value;
434 			    break;
435 			case RL2_SAMPLE_FLOAT:
436 			    flt_value = (float) dbl_value;
437 			    *p_float++ = flt_value;
438 			    break;
439 			case RL2_SAMPLE_DOUBLE:
440 			    *p_double++ = dbl_value;
441 			    break;
442 			};
443 		      col_no++;
444 		      if (col_no == ascii->width)
445 			  fwrite (scanline, sz, 1, ascii->tmp);
446 		  }
447 		p_out = buf;
448 		if (c == '\n')
449 		    new_line = 1;
450 		continue;
451 	    }
452 
453 	  if ((p_out - buf) >= 1024)
454 	      goto error;
455 	  *p_out++ = c;
456       }
457     if (line_no != height)
458 	goto error;
459 
460     fclose (in);
461     free (scanline);
462     return (rl2AsciiGridOriginPtr) ascii;
463 
464   error:
465     if (scanline != NULL)
466 	free (scanline);
467     if (ascii != NULL)
468 	rl2_destroy_ascii_grid_origin ((rl2AsciiGridOriginPtr) ascii);
469     if (in != NULL)
470 	fclose (in);
471     return NULL;
472 }
473 
474 RL2_DECLARE void
rl2_destroy_ascii_grid_origin(rl2AsciiGridOriginPtr ascii)475 rl2_destroy_ascii_grid_origin (rl2AsciiGridOriginPtr ascii)
476 {
477 /* memory cleanup - destroying an ASCII Grid Origin object */
478     rl2PrivAsciiOriginPtr org = (rl2PrivAsciiOriginPtr) ascii;
479     if (org == NULL)
480 	return;
481     if (org->path != NULL)
482 	free (org->path);
483     if (org->tmp != NULL)
484 	fclose (org->tmp);
485     free (org);
486 }
487 
488 RL2_DECLARE const char *
rl2_get_ascii_grid_origin_path(rl2AsciiGridOriginPtr ascii)489 rl2_get_ascii_grid_origin_path (rl2AsciiGridOriginPtr ascii)
490 {
491 /* retrieving the input path from an ASCII Grid origin */
492     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
493     if (origin == NULL)
494 	return NULL;
495 
496     return origin->path;
497 }
498 
499 RL2_DECLARE int
rl2_get_ascii_grid_origin_size(rl2AsciiGridOriginPtr ascii,unsigned int * width,unsigned int * height)500 rl2_get_ascii_grid_origin_size (rl2AsciiGridOriginPtr ascii,
501 				unsigned int *width, unsigned int *height)
502 {
503 /* retrieving Width and Height from an ASCII Grid origin */
504     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
505     if (origin == NULL)
506 	return RL2_ERROR;
507 
508     *width = origin->width;
509     *height = origin->height;
510     return RL2_OK;
511 }
512 
513 RL2_DECLARE int
rl2_get_ascii_grid_origin_srid(rl2AsciiGridOriginPtr ascii,int * srid)514 rl2_get_ascii_grid_origin_srid (rl2AsciiGridOriginPtr ascii, int *srid)
515 {
516 /* retrieving the SRID from an ASCII Grid origin */
517     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
518     if (origin == NULL)
519 	return RL2_ERROR;
520 
521     *srid = origin->Srid;
522     return RL2_OK;
523 }
524 
525 RL2_DECLARE int
rl2_get_ascii_grid_origin_extent(rl2AsciiGridOriginPtr ascii,double * minX,double * minY,double * maxX,double * maxY)526 rl2_get_ascii_grid_origin_extent (rl2AsciiGridOriginPtr ascii, double *minX,
527 				  double *minY, double *maxX, double *maxY)
528 {
529 /* retrieving the Extent from an ASCII Grid origin */
530     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
531     if (origin == NULL)
532 	return RL2_ERROR;
533 
534     *minX = origin->minX;
535     *minY = origin->minY;
536     *maxX = origin->maxX;
537     *maxY = origin->maxY;
538     return RL2_OK;
539 }
540 
541 RL2_DECLARE int
rl2_get_ascii_grid_origin_resolution(rl2AsciiGridOriginPtr ascii,double * hResolution,double * vResolution)542 rl2_get_ascii_grid_origin_resolution (rl2AsciiGridOriginPtr ascii,
543 				      double *hResolution, double *vResolution)
544 {
545 /* retrieving the Pixel Resolution from an ASCII Grid origin */
546     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
547     if (origin == NULL)
548 	return RL2_ERROR;
549 
550     *hResolution = origin->hResolution;
551     *vResolution = origin->vResolution;
552     return RL2_OK;
553 }
554 
555 RL2_DECLARE int
rl2_get_ascii_grid_origin_type(rl2AsciiGridOriginPtr ascii,unsigned char * sample_type,unsigned char * pixel_type,unsigned char * num_bands)556 rl2_get_ascii_grid_origin_type (rl2AsciiGridOriginPtr ascii,
557 				unsigned char *sample_type,
558 				unsigned char *pixel_type,
559 				unsigned char *num_bands)
560 {
561 /* retrieving the sample/pixel type from an ASCII Grid origin */
562     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
563     if (origin == NULL)
564 	return RL2_ERROR;
565 
566     *sample_type = origin->sample_type;
567     *pixel_type = RL2_PIXEL_DATAGRID;
568     *num_bands = 1;
569     return RL2_OK;
570 }
571 
572 RL2_DECLARE int
rl2_eval_ascii_grid_origin_compatibility(rl2CoveragePtr cvg,rl2AsciiGridOriginPtr ascii)573 rl2_eval_ascii_grid_origin_compatibility (rl2CoveragePtr cvg,
574 					  rl2AsciiGridOriginPtr ascii)
575 {
576 /* testing if a Coverage and an ASCII Grid origin are mutually compatible */
577     unsigned char sample_type;
578     unsigned char pixel_type;
579     unsigned char num_bands;
580     int srid;
581     double hResolution;
582     double vResolution;
583     double confidence;
584     rl2PrivCoveragePtr coverage = (rl2PrivCoveragePtr) cvg;
585 
586     if (coverage == NULL || ascii == NULL)
587 	return RL2_ERROR;
588     if (rl2_get_ascii_grid_origin_type
589 	(ascii, &sample_type, &pixel_type, &num_bands) != RL2_OK)
590 	return RL2_ERROR;
591 
592     if (coverage->sampleType != sample_type)
593 	return RL2_FALSE;
594     if (coverage->pixelType != pixel_type)
595 	return RL2_FALSE;
596     if (coverage->nBands != num_bands)
597 	return RL2_FALSE;
598 
599 /* checking for resolution compatibility */
600     if (rl2_get_ascii_grid_origin_srid (ascii, &srid) != RL2_OK)
601 	return RL2_FALSE;
602     if (coverage->Srid != srid)
603 	return RL2_FALSE;
604     if (rl2_get_ascii_grid_origin_resolution (ascii, &hResolution, &vResolution)
605 	!= RL2_OK)
606 	return RL2_FALSE;
607     confidence = coverage->hResolution / 100.0;
608     if (hResolution < (coverage->hResolution - confidence)
609 	|| hResolution > (coverage->hResolution + confidence))
610 	return RL2_FALSE;
611     confidence = coverage->vResolution / 100.0;
612     if (vResolution < (coverage->vResolution - confidence)
613 	|| vResolution > (coverage->vResolution + confidence))
614 	return RL2_FALSE;
615     return RL2_TRUE;
616 }
617 
618 static int
read_ascii_int8(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,char * pixels)619 read_ascii_int8 (rl2PrivAsciiOriginPtr origin, unsigned int width,
620 		 unsigned int height, unsigned int startRow,
621 		 unsigned int startCol, char *pixels)
622 {
623 /* reading from the Temporary helper file - INT8 */
624     unsigned int x;
625     unsigned int y;
626     unsigned int row;
627     unsigned int col;
628     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
629       {
630 	  /* looping on rows */
631 	  long offset = (row * origin->width) + startCol;
632 	  char *p_out = pixels + (y * width);
633 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
634 	      return 0;
635 	  for (x = 0, col = startCol; x < width && col < origin->width;
636 	       x++, col++)
637 	    {
638 		char int8;
639 		if (fread (&int8, sizeof (char), 1, origin->tmp) <= 0)
640 		    return 0;
641 		*p_out++ = int8;
642 	    }
643       }
644     return 1;
645 }
646 
647 static int
read_ascii_uint8(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,unsigned char * pixels)648 read_ascii_uint8 (rl2PrivAsciiOriginPtr origin, unsigned int width,
649 		  unsigned int height, unsigned int startRow,
650 		  unsigned int startCol, unsigned char *pixels)
651 {
652 /* reading from the Temporary helper file - UINT8 */
653     unsigned int x;
654     unsigned int y;
655     unsigned int row;
656     unsigned int col;
657     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
658       {
659 	  /* looping on rows */
660 	  long offset = (row * origin->width) + startCol;
661 	  unsigned char *p_out = pixels + (y * width);
662 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
663 	      return 0;
664 	  for (x = 0, col = startCol; x < width && col < origin->width;
665 	       x++, col++)
666 	    {
667 		unsigned char uint8;
668 		if (fread (&uint8, sizeof (unsigned char), 1, origin->tmp) <= 0)
669 		    return 0;
670 		*p_out++ = uint8;
671 	    }
672       }
673     return 1;
674 }
675 
676 static int
read_ascii_int16(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,short * pixels)677 read_ascii_int16 (rl2PrivAsciiOriginPtr origin, unsigned int width,
678 		  unsigned int height, unsigned int startRow,
679 		  unsigned int startCol, short *pixels)
680 {
681 /* reading from the Temporary helper file - INT16 */
682     unsigned int x;
683     unsigned int y;
684     unsigned int row;
685     unsigned int col;
686     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
687       {
688 	  /* looping on rows */
689 	  long offset =
690 	      (row * origin->width * sizeof (short)) +
691 	      (startCol * sizeof (short));
692 	  short *p_out = pixels + (y * width);
693 	  if (fseek (origin->tmp, offset, SEEK_SET) < 0)
694 	      return 0;
695 	  for (x = 0, col = startCol; x < width && col < origin->width;
696 	       x++, col++)
697 	    {
698 		short int16;
699 		if (fread (&int16, sizeof (short), 1, origin->tmp) <= 0)
700 		    return 0;
701 		*p_out++ = int16;
702 	    }
703       }
704     return 1;
705 }
706 
707 static int
read_ascii_uint16(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,unsigned short * pixels)708 read_ascii_uint16 (rl2PrivAsciiOriginPtr origin, unsigned int width,
709 		   unsigned int height, unsigned int startRow,
710 		   unsigned int startCol, unsigned short *pixels)
711 {
712 /* reading from the Temporary helper file - UINT16 */
713     unsigned int x;
714     unsigned int y;
715     unsigned int row;
716     unsigned int col;
717     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
718       {
719 	  /* looping on rows */
720 	  long offset =
721 	      (row * origin->width * sizeof (unsigned short)) +
722 	      (startCol * sizeof (unsigned short));
723 	  unsigned short *p_out = pixels + (y * width);
724 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
725 	      return 0;
726 	  for (x = 0, col = startCol; x < width && col < origin->width;
727 	       x++, col++)
728 	    {
729 		unsigned short uint16;
730 		if (fread (&uint16, sizeof (unsigned short), 1, origin->tmp) <=
731 		    0)
732 		    return 0;
733 		*p_out++ = uint16;
734 	    }
735       }
736     return 1;
737 }
738 
739 static int
read_ascii_int32(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,int * pixels)740 read_ascii_int32 (rl2PrivAsciiOriginPtr origin, unsigned int width,
741 		  unsigned int height, unsigned int startRow,
742 		  unsigned int startCol, int *pixels)
743 {
744 /* reading from the Temporary helper file - INT32 */
745     unsigned int x;
746     unsigned int y;
747     unsigned int row;
748     unsigned int col;
749     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
750       {
751 	  /* looping on rows */
752 	  long offset =
753 	      (row * origin->width * sizeof (int)) + (startCol * sizeof (int));
754 	  int *p_out = pixels + (y * width);
755 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
756 	      return 0;
757 	  for (x = 0, col = startCol; x < width && col < origin->width;
758 	       x++, col++)
759 	    {
760 		int int32;
761 		if (fread (&int32, sizeof (int), 1, origin->tmp) <= 0)
762 		    return 0;
763 		*p_out++ = int32;
764 	    }
765       }
766     return 1;
767 }
768 
769 static int
read_ascii_uint32(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,unsigned int * pixels)770 read_ascii_uint32 (rl2PrivAsciiOriginPtr origin, unsigned int width,
771 		   unsigned int height, unsigned int startRow,
772 		   unsigned int startCol, unsigned int *pixels)
773 {
774 /* reading from the Temporary helper file - UINT32 */
775     unsigned int x;
776     unsigned int y;
777     unsigned int row;
778     unsigned int col;
779     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
780       {
781 	  /* looping on rows */
782 	  long offset =
783 	      (row * origin->width * sizeof (unsigned int)) +
784 	      (startCol * sizeof (unsigned int));
785 	  unsigned int *p_out = pixels + (y * width);
786 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
787 	      return 0;
788 	  for (x = 0, col = startCol; x < width && col < origin->width;
789 	       x++, col++)
790 	    {
791 		unsigned int uint32;
792 		if (fread (&uint32, sizeof (unsigned int), 1, origin->tmp) <= 0)
793 		    return 0;
794 		*p_out++ = uint32;
795 	    }
796       }
797     return 1;
798 }
799 
800 static int
read_ascii_float(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,float * pixels)801 read_ascii_float (rl2PrivAsciiOriginPtr origin, unsigned int width,
802 		  unsigned int height, unsigned int startRow,
803 		  unsigned int startCol, float *pixels)
804 {
805 /* reading from the Temporary helper file - FLOAT */
806     unsigned int x;
807     unsigned int y;
808     unsigned int row;
809     unsigned int col;
810     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
811       {
812 	  /* looping on rows */
813 	  long offset =
814 	      (row * origin->width * sizeof (float)) +
815 	      (startCol * sizeof (float));
816 	  float *p_out = pixels + (y * width);
817 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
818 	      return 0;
819 	  for (x = 0, col = startCol; x < width && col < origin->width;
820 	       x++, col++)
821 	    {
822 		float flt;
823 		if (fread (&flt, sizeof (float), 1, origin->tmp) <= 0)
824 		    return 0;
825 		*p_out++ = flt;
826 	    }
827       }
828     return 1;
829 }
830 
831 static int
read_ascii_double(rl2PrivAsciiOriginPtr origin,unsigned int width,unsigned int height,unsigned int startRow,unsigned int startCol,double * pixels)832 read_ascii_double (rl2PrivAsciiOriginPtr origin, unsigned int width,
833 		   unsigned int height, unsigned int startRow,
834 		   unsigned int startCol, double *pixels)
835 {
836 /* reading from the Temporary helper file - DOUBLE */
837     unsigned int x;
838     unsigned int y;
839     unsigned int row;
840     unsigned int col;
841     for (y = 0, row = startRow; y < height && row < origin->height; y++, row++)
842       {
843 	  /* looping on rows */
844 	  long offset =
845 	      (row * origin->width * sizeof (double)) +
846 	      (startCol * sizeof (double));
847 	  double *p_out = pixels + (y * width);
848 	  if (fseek (origin->tmp, offset, SEEK_SET) != 0)
849 	      return 0;
850 	  for (x = 0, col = startCol; x < width && col < origin->width;
851 	       x++, col++)
852 	    {
853 		double dbl;
854 		if (fread (&dbl, sizeof (double), 1, origin->tmp) <= 0)
855 		    return 0;
856 		*p_out++ = dbl;
857 	    }
858       }
859     return 1;
860 }
861 
862 static int
read_ascii_pixels(rl2PrivAsciiOriginPtr origin,unsigned short width,unsigned short height,unsigned char sample_type,unsigned int startRow,unsigned int startCol,void * pixels)863 read_ascii_pixels (rl2PrivAsciiOriginPtr origin, unsigned short width,
864 		   unsigned short height, unsigned char sample_type,
865 		   unsigned int startRow, unsigned int startCol, void *pixels)
866 {
867 /* reading from the Temporary helper file */
868     switch (sample_type)
869       {
870       case RL2_SAMPLE_INT8:
871 	  return read_ascii_int8 (origin, width, height, startRow, startCol,
872 				  (char *) pixels);
873       case RL2_SAMPLE_UINT8:
874 	  return read_ascii_uint8 (origin, width, height, startRow, startCol,
875 				   (unsigned char *) pixels);
876       case RL2_SAMPLE_INT16:
877 	  return read_ascii_int16 (origin, width, height, startRow, startCol,
878 				   (short *) pixels);
879       case RL2_SAMPLE_UINT16:
880 	  return read_ascii_uint16 (origin, width, height, startRow, startCol,
881 				    (unsigned short *) pixels);
882       case RL2_SAMPLE_INT32:
883 	  return read_ascii_int32 (origin, width, height, startRow, startCol,
884 				   (int *) pixels);
885       case RL2_SAMPLE_UINT32:
886 	  return read_ascii_uint32 (origin, width, height, startRow, startCol,
887 				    (unsigned int *) pixels);
888       case RL2_SAMPLE_FLOAT:
889 	  return read_ascii_float (origin, width, height, startRow, startCol,
890 				   (float *) pixels);
891       case RL2_SAMPLE_DOUBLE:
892 	  return read_ascii_double (origin, width, height, startRow, startCol,
893 				    (double *) pixels);
894       };
895     return 0;
896 }
897 
898 static int
read_from_ascii(rl2PrivAsciiOriginPtr origin,unsigned short width,unsigned short height,unsigned char sample_type,unsigned int startRow,unsigned int startCol,unsigned char ** pixels,int * pixels_sz)899 read_from_ascii (rl2PrivAsciiOriginPtr origin, unsigned short width,
900 		 unsigned short height, unsigned char sample_type,
901 		 unsigned int startRow, unsigned int startCol,
902 		 unsigned char **pixels, int *pixels_sz)
903 {
904 /* creating a tile from the ASCII Grid origin */
905     unsigned char *bufPixels = NULL;
906     int bufPixelsSz = 0;
907     int pix_sz = 1;
908     rl2PixelPtr no_data = NULL;
909 
910     no_data = rl2_create_pixel (sample_type, RL2_PIXEL_DATAGRID, 1);
911 
912 /* allocating the pixels buffer */
913     switch (sample_type)
914       {
915       case RL2_SAMPLE_INT8:
916 	  pix_sz = 1;
917 	  rl2_set_pixel_sample_int8 (no_data, (char) (origin->noData));
918 	  break;
919       case RL2_SAMPLE_UINT8:
920 	  pix_sz = 1;
921 	  rl2_set_pixel_sample_uint8 (no_data, 0,
922 				      (unsigned char) (origin->noData));
923 	  break;
924       case RL2_SAMPLE_INT16:
925 	  rl2_set_pixel_sample_int16 (no_data, (short) (origin->noData));
926 	  pix_sz = 2;
927 	  break;
928       case RL2_SAMPLE_UINT16:
929 	  rl2_set_pixel_sample_uint16 (no_data, 0,
930 				       (unsigned short) (origin->noData));
931 	  pix_sz = 2;
932 	  break;
933       case RL2_SAMPLE_INT32:
934 	  pix_sz = 4;
935 	  rl2_set_pixel_sample_int32 (no_data, (int) (origin->noData));
936 	  break;
937       case RL2_SAMPLE_UINT32:
938 	  pix_sz = 4;
939 	  rl2_set_pixel_sample_uint32 (no_data,
940 				       (unsigned int) (origin->noData));
941 	  break;
942       case RL2_SAMPLE_FLOAT:
943 	  pix_sz = 4;
944 	  rl2_set_pixel_sample_float (no_data, (float) (origin->noData));
945 	  break;
946       case RL2_SAMPLE_DOUBLE:
947 	  pix_sz = 8;
948 	  rl2_set_pixel_sample_double (no_data, (double) (origin->noData));
949 	  break;
950       };
951     bufPixelsSz = width * height * pix_sz;
952     bufPixels = malloc (bufPixelsSz);
953     if (bufPixels == NULL)
954 	goto error;
955     if ((startRow + height) > origin->height
956 	|| (startCol + width) > origin->width)
957 	rl2_prime_void_tile (bufPixels, width, height, sample_type, 1, no_data);
958 
959     if (!read_ascii_pixels
960 	(origin, width, height, sample_type, startRow, startCol, bufPixels))
961 	goto error;
962 
963     rl2_destroy_pixel (no_data);
964     *pixels = bufPixels;
965     *pixels_sz = bufPixelsSz;
966     return RL2_OK;
967   error:
968     if (bufPixels != NULL)
969 	free (bufPixels);
970     if (no_data != NULL)
971 	rl2_destroy_pixel (no_data);
972     return RL2_ERROR;
973 }
974 
975 RL2_DECLARE rl2RasterPtr
rl2_get_tile_from_ascii_grid_origin(rl2CoveragePtr cvg,rl2AsciiGridOriginPtr ascii,unsigned int startRow,unsigned int startCol)976 rl2_get_tile_from_ascii_grid_origin (rl2CoveragePtr cvg,
977 				     rl2AsciiGridOriginPtr ascii,
978 				     unsigned int startRow,
979 				     unsigned int startCol)
980 {
981 /* attempting to create a Coverage-tile from an ASCII Grid origin */
982     unsigned int x;
983     rl2PrivCoveragePtr coverage = (rl2PrivCoveragePtr) cvg;
984     rl2PrivAsciiOriginPtr origin = (rl2PrivAsciiOriginPtr) ascii;
985     rl2RasterPtr raster = NULL;
986     unsigned char *pixels = NULL;
987     int pixels_sz = 0;
988     unsigned char *mask = NULL;
989     int mask_size = 0;
990     unsigned int unused_width = 0;
991     unsigned int unused_height = 0;
992 
993     if (coverage == NULL || origin == NULL)
994 	return NULL;
995     if (rl2_eval_ascii_grid_origin_compatibility (cvg, ascii) != RL2_TRUE)
996 	return NULL;
997     if (origin->tmp == NULL)
998 	return NULL;
999 
1000 /* testing for tile's boundary validity */
1001     if (startCol > origin->width)
1002 	return NULL;
1003     if (startRow > origin->height)
1004 	return NULL;
1005     x = startCol / coverage->tileWidth;
1006     if ((x * coverage->tileWidth) != startCol)
1007 	return NULL;
1008     x = startRow / coverage->tileHeight;
1009     if ((x * coverage->tileHeight) != startRow)
1010 	return NULL;
1011 
1012 /* attempting to create the tile */
1013     if (read_from_ascii
1014 	(origin, coverage->tileWidth, coverage->tileHeight,
1015 	 coverage->sampleType, startRow, startCol, &pixels,
1016 	 &pixels_sz) != RL2_OK)
1017 	goto error;
1018     if (startCol + coverage->tileWidth > origin->width)
1019 	unused_width = (startCol + coverage->tileWidth) - origin->width;
1020     if (startRow + coverage->tileHeight > origin->height)
1021 	unused_height = (startRow + coverage->tileHeight) - origin->height;
1022     if (unused_width || unused_height)
1023       {
1024 	  /*
1025 	   * creating a Transparency Mask so to shadow any
1026 	   * unused portion of the current tile
1027 	   */
1028 	  unsigned int shadow_x = coverage->tileWidth - unused_width;
1029 	  unsigned int shadow_y = coverage->tileHeight - unused_height;
1030 	  unsigned int row;
1031 	  mask_size = coverage->tileWidth * coverage->tileHeight;
1032 	  mask = malloc (mask_size);
1033 	  if (mask == NULL)
1034 	      goto error;
1035 	  /* full Transparent mask */
1036 	  memset (mask, 0, coverage->tileWidth * coverage->tileHeight);
1037 	  for (row = 0; row < coverage->tileHeight; row++)
1038 	    {
1039 		unsigned char *p = mask + (row * coverage->tileWidth);
1040 		if (row < shadow_y)
1041 		  {
1042 		      /* setting opaque pixels */
1043 		      memset (p, 1, shadow_x);
1044 		  }
1045 	    }
1046       }
1047     raster =
1048 	rl2_create_raster (coverage->tileWidth, coverage->tileHeight,
1049 			   coverage->sampleType, RL2_PIXEL_DATAGRID, 1, pixels,
1050 			   pixels_sz, NULL, mask, mask_size, NULL);
1051     if (raster == NULL)
1052 	goto error;
1053     return raster;
1054   error:
1055     if (pixels != NULL)
1056 	free (pixels);
1057     if (mask != NULL)
1058 	free (mask);
1059     return NULL;
1060 }
1061 
1062 static rl2PrivAsciiDestinationPtr
alloc_ascii_destination(const char * path,unsigned int width,unsigned int height,double x,double y,double res,int is_centered,double no_data,int decimal_digits)1063 alloc_ascii_destination (const char *path, unsigned int width,
1064 			 unsigned int height, double x, double y,
1065 			 double res, int is_centered, double no_data,
1066 			 int decimal_digits)
1067 {
1068 /* allocating and initializing an ASCII Grid detination */
1069     int len;
1070     rl2PrivAsciiDestinationPtr ascii =
1071 	malloc (sizeof (rl2PrivAsciiDestination));
1072     if (ascii == NULL)
1073 	return NULL;
1074     len = strlen (path);
1075     ascii->path = malloc (len + 1);
1076     strcpy (ascii->path, path);
1077     ascii->out = NULL;
1078     ascii->width = width;
1079     ascii->height = height;
1080     ascii->Resolution = res;
1081     ascii->X = x;
1082     ascii->Y = y;
1083     ascii->isCentered = is_centered;
1084     ascii->noData = no_data;
1085     if (decimal_digits < 0)
1086 	ascii->decimalDigits = 0;
1087     else if (decimal_digits > 18)
1088 	ascii->decimalDigits = 18;
1089     else
1090 	ascii->decimalDigits = decimal_digits;
1091     ascii->headerDone = 'N';
1092     ascii->nextLineNo = 0;
1093     ascii->pixels = NULL;
1094     ascii->sampleType = RL2_SAMPLE_UNKNOWN;
1095     return ascii;
1096 }
1097 
1098 RL2_DECLARE rl2AsciiGridDestinationPtr
rl2_create_ascii_grid_destination(const char * path,unsigned int width,unsigned int height,double resolution,double x,double y,int is_centered,double no_data,int decimal_digits,void * pixels,int pixels_size,unsigned char sample_type)1099 rl2_create_ascii_grid_destination (const char *path, unsigned int width,
1100 				   unsigned int height, double resolution,
1101 				   double x, double y, int is_centered,
1102 				   double no_data, int decimal_digits,
1103 				   void *pixels, int pixels_size,
1104 				   unsigned char sample_type)
1105 {
1106 /* creating an ASCII Grid Destination */
1107     FILE *out;
1108     rl2PrivAsciiDestinationPtr ascii = NULL;
1109     int pix_sz = 0;
1110 
1111     if (path == NULL)
1112 	return NULL;
1113     if (pixels == NULL)
1114 	return NULL;
1115 
1116     switch (sample_type)
1117       {
1118       case RL2_SAMPLE_INT8:
1119       case RL2_SAMPLE_UINT8:
1120 	  pix_sz = 1;
1121 	  break;
1122       case RL2_SAMPLE_INT16:
1123       case RL2_SAMPLE_UINT16:
1124 	  pix_sz = 2;
1125 	  break;
1126       case RL2_SAMPLE_INT32:
1127       case RL2_SAMPLE_UINT32:
1128       case RL2_SAMPLE_FLOAT:
1129 	  pix_sz = 4;
1130 	  break;
1131       case RL2_SAMPLE_DOUBLE:
1132 	  pix_sz = 8;
1133 	  break;
1134       };
1135     if (pix_sz < 1)
1136 	return NULL;
1137     if (pixels_size != (int) (width * height * pix_sz))
1138 	return NULL;
1139 
1140     out = fopen (path, "w");
1141     if (out == NULL)
1142       {
1143 	  fprintf (stderr, "ASCII Destination: Unable to open %s\n", path);
1144 	  return NULL;
1145       }
1146 
1147     ascii =
1148 	alloc_ascii_destination (path, width, height, x, y, resolution,
1149 				 is_centered, no_data, decimal_digits);
1150     if (ascii == NULL)
1151 	goto error;
1152 
1153 /* creating the output File */
1154     out = fopen (path, "wb");
1155     if (out == NULL)
1156 	goto error;
1157     ascii->out = out;
1158     ascii->pixels = pixels;
1159     ascii->sampleType = sample_type;
1160 
1161     return (rl2AsciiGridDestinationPtr) ascii;
1162 
1163   error:
1164     if (ascii != NULL)
1165 	rl2_destroy_ascii_grid_destination ((rl2AsciiGridDestinationPtr) ascii);
1166     if (out != NULL)
1167 	fclose (out);
1168     return NULL;
1169 }
1170 
1171 RL2_DECLARE void
rl2_destroy_ascii_grid_destination(rl2AsciiGridDestinationPtr ascii)1172 rl2_destroy_ascii_grid_destination (rl2AsciiGridDestinationPtr ascii)
1173 {
1174 /* memory cleanup - destroying an ASCII Grid destination object */
1175     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1176     if (dst == NULL)
1177 	return;
1178     if (dst->path != NULL)
1179 	free (dst->path);
1180     if (dst->out != NULL)
1181 	fclose (dst->out);
1182     if (dst->pixels != NULL)
1183 	free (dst->pixels);
1184     free (dst);
1185 }
1186 
1187 RL2_DECLARE const char *
rl2_get_ascii_grid_destination_path(rl2AsciiGridDestinationPtr ascii)1188 rl2_get_ascii_grid_destination_path (rl2AsciiGridDestinationPtr ascii)
1189 {
1190 /* retrieving the input path from an ASCII Grid destination */
1191     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1192     if (dst == NULL)
1193 	return NULL;
1194 
1195     return dst->path;
1196 }
1197 
1198 RL2_DECLARE int
rl2_get_ascii_grid_destination_size(rl2AsciiGridDestinationPtr ascii,unsigned int * width,unsigned int * height)1199 rl2_get_ascii_grid_destination_size (rl2AsciiGridDestinationPtr ascii,
1200 				     unsigned int *width, unsigned int *height)
1201 {
1202 /* retrieving Width and Height from an ASCII Grid destination */
1203     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1204     if (dst == NULL)
1205 	return RL2_ERROR;
1206 
1207     *width = dst->width;
1208     *height = dst->height;
1209     return RL2_OK;
1210 }
1211 
1212 RL2_DECLARE int
rl2_get_ascii_grid_destination_tiepoint(rl2AsciiGridDestinationPtr ascii,double * X,double * Y)1213 rl2_get_ascii_grid_destination_tiepoint (rl2AsciiGridDestinationPtr ascii,
1214 					 double *X, double *Y)
1215 {
1216 /* retrieving the tiepoint from an ASCII Grid destination */
1217     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1218     if (dst == NULL)
1219 	return RL2_ERROR;
1220 
1221     *X = dst->X;
1222     *Y = dst->Y;
1223     return RL2_OK;
1224 }
1225 
1226 RL2_DECLARE int
rl2_get_ascii_grid_destination_resolution(rl2AsciiGridDestinationPtr ascii,double * resolution)1227 rl2_get_ascii_grid_destination_resolution (rl2AsciiGridDestinationPtr ascii,
1228 					   double *resolution)
1229 {
1230 /* retrieving the Pixel Resolution from an ASCII Grid destination */
1231     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1232     if (dst == NULL)
1233 	return RL2_ERROR;
1234 
1235     *resolution = dst->Resolution;
1236     return RL2_OK;
1237 }
1238 
1239 RL2_DECLARE int
rl2_write_ascii_grid_header(rl2AsciiGridDestinationPtr ascii)1240 rl2_write_ascii_grid_header (rl2AsciiGridDestinationPtr ascii)
1241 {
1242 /* attempting to write the ASCII Grid header */
1243     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1244     if (dst == NULL)
1245 	return RL2_ERROR;
1246     if (dst->out == NULL)
1247 	return RL2_ERROR;
1248     if (dst->headerDone != 'N')
1249 	return RL2_ERROR;
1250 
1251     fprintf (dst->out, "ncols %u\r\n", dst->width);
1252     fprintf (dst->out, "nrows %u\r\n", dst->height);
1253     if (dst->isCentered)
1254       {
1255 	  fprintf (dst->out, "xllcenter %1.8f\r\n", dst->X);
1256 	  fprintf (dst->out, "yllcenter %1.8f\r\n", dst->Y);
1257       }
1258     else
1259       {
1260 	  fprintf (dst->out, "xllcorner %1.8f\r\n", dst->X);
1261 	  fprintf (dst->out, "yllcorner %1.8f\r\n", dst->Y);
1262       }
1263     fprintf (dst->out, "cellsize %1.8f\r\n", dst->Resolution);
1264     fprintf (dst->out, "NODATA_value %1.8f\r\n", dst->noData);
1265     dst->headerDone = 'Y';
1266     return RL2_OK;
1267 }
1268 
1269 static char *
format_pixel(double cell_value,int decimal_digits)1270 format_pixel (double cell_value, int decimal_digits)
1271 {
1272 /* well formatting an ASCII pixel */
1273     char format[32];
1274     char *pixel;
1275     char *p;
1276     sprintf (format, " %%1.%df", decimal_digits);
1277     pixel = sqlite3_mprintf (format, cell_value);
1278     if (decimal_digits == 0)
1279 	return pixel;
1280     p = pixel + strlen (pixel) - 1;
1281     while (1)
1282       {
1283 	  if (*p == '0')
1284 	      *p = '\0';
1285 	  else if (*p == '.')
1286 	    {
1287 		*p = '\0';
1288 		break;
1289 	    }
1290 	  else
1291 	      break;
1292 	  p--;
1293       }
1294     return pixel;
1295 }
1296 
1297 RL2_DECLARE int
rl2_write_ascii_grid_scanline(rl2AsciiGridDestinationPtr ascii,unsigned int * line_no)1298 rl2_write_ascii_grid_scanline (rl2AsciiGridDestinationPtr ascii,
1299 			       unsigned int *line_no)
1300 {
1301 /* attempting to write a scanline into an ASCII Grid */
1302     char *p8;
1303     unsigned char *pu8;
1304     short *p16;
1305     unsigned short *pu16;
1306     int *p32;
1307     unsigned int *pu32;
1308     float *pflt;
1309     double *pdbl;
1310     double cell_value;
1311     char *pxl;
1312     unsigned int x;
1313     rl2PrivAsciiDestinationPtr dst = (rl2PrivAsciiDestinationPtr) ascii;
1314 
1315     if (dst == NULL)
1316 	return RL2_ERROR;
1317     if (dst->out == NULL)
1318 	return RL2_ERROR;
1319     if (dst->headerDone != 'Y')
1320 	return RL2_ERROR;
1321     if (dst->nextLineNo >= dst->height)
1322 	return RL2_ERROR;
1323 
1324     switch (dst->sampleType)
1325       {
1326       case RL2_SAMPLE_INT8:
1327 	  p8 = dst->pixels;
1328 	  p8 += (dst->nextLineNo * dst->width);
1329 	  break;
1330       case RL2_SAMPLE_UINT8:
1331 	  pu8 = dst->pixels;
1332 	  pu8 += (dst->nextLineNo * dst->width);
1333 	  break;
1334       case RL2_SAMPLE_INT16:
1335 	  p16 = dst->pixels;
1336 	  p16 += (dst->nextLineNo * dst->width);
1337 	  break;
1338       case RL2_SAMPLE_UINT16:
1339 	  pu16 = dst->pixels;
1340 	  pu16 += (dst->nextLineNo * dst->width);
1341 	  break;
1342       case RL2_SAMPLE_INT32:
1343 	  p32 = dst->pixels;
1344 	  p32 += (dst->nextLineNo * dst->width);
1345 	  break;
1346       case RL2_SAMPLE_UINT32:
1347 	  pu32 = dst->pixels;
1348 	  pu32 += (dst->nextLineNo * dst->width);
1349 	  break;
1350       case RL2_SAMPLE_FLOAT:
1351 	  pflt = dst->pixels;
1352 	  pflt += (dst->nextLineNo * dst->width);
1353 	  break;
1354       case RL2_SAMPLE_DOUBLE:
1355 	  pdbl = dst->pixels;
1356 	  pdbl += (dst->nextLineNo * dst->width);
1357 	  break;
1358       };
1359 
1360     for (x = 0; x < dst->width; x++)
1361       {
1362 	  switch (dst->sampleType)
1363 	    {
1364 	    case RL2_SAMPLE_INT8:
1365 		cell_value = *p8++;
1366 		break;
1367 	    case RL2_SAMPLE_UINT8:
1368 		cell_value = *pu8++;
1369 		break;
1370 	    case RL2_SAMPLE_INT16:
1371 		cell_value = *p16++;
1372 		break;
1373 	    case RL2_SAMPLE_UINT16:
1374 		cell_value = *pu16++;
1375 		break;
1376 	    case RL2_SAMPLE_INT32:
1377 		cell_value = *p32++;
1378 		break;
1379 	    case RL2_SAMPLE_UINT32:
1380 		cell_value = *pu32++;
1381 		break;
1382 	    case RL2_SAMPLE_FLOAT:
1383 		cell_value = *pflt++;
1384 		break;
1385 	    case RL2_SAMPLE_DOUBLE:
1386 		cell_value = *pdbl++;
1387 		break;
1388 	    };
1389 	  pxl = format_pixel (cell_value, dst->decimalDigits);
1390 	  fprintf (dst->out, "%s", pxl);
1391 	  sqlite3_free (pxl);
1392       }
1393     fprintf (dst->out, "\r\n");
1394 
1395     dst->nextLineNo += 1;
1396     *line_no = dst->nextLineNo;
1397     return RL2_OK;
1398 }
1399