1 /*
2  *
3  * WKTRaster - Raster Types for PostGIS
4  * http://trac.osgeo.org/postgis/wiki/WKTRaster
5  *
6  * Copyright (C) 2011-2013 Regents of the University of California
7  *   <bkpark@ucdavis.edu>
8  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
9  * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
10  * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
11  * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
12  * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27  *
28  */
29 
30 #include "librtcore.h"
31 #include "librtcore_internal.h"
32 #include "rt_serialize.h"
33 
34 /******************************************************************************
35 * Debug and Testing Utilities
36 ******************************************************************************/
37 
38 #if POSTGIS_DEBUG_LEVEL > 2
39 
40 char*
d_binary_to_hex(const uint8_t * const raw,uint32_t size,uint32_t * hexsize)41 d_binary_to_hex(const uint8_t * const raw, uint32_t size, uint32_t *hexsize) {
42     char* hex = NULL;
43     uint32_t i = 0;
44 
45 
46     assert(NULL != raw);
47     assert(NULL != hexsize);
48 
49 
50     *hexsize = size * 2; /* hex is 2 times bytes */
51     hex = (char*) rtalloc((*hexsize) + 1);
52     if (!hex) {
53         rterror("d_binary_to_hex: Out of memory hexifying raw binary");
54         return NULL;
55     }
56     hex[*hexsize] = '\0'; /* Null-terminate */
57 
58     for (i = 0; i < size; ++i) {
59         deparse_hex(raw[i], &(hex[2 * i]));
60     }
61 
62     assert(NULL != hex);
63     assert(0 == strlen(hex) % 2);
64     return hex;
65 }
66 
67 void
d_print_binary_hex(const char * msg,const uint8_t * const raw,uint32_t size)68 d_print_binary_hex(const char* msg, const uint8_t * const raw, uint32_t size) {
69     char* hex = NULL;
70     uint32_t hexsize = 0;
71 
72 
73     assert(NULL != msg);
74     assert(NULL != raw);
75 
76 
77     hex = d_binary_to_hex(raw, size, &hexsize);
78     if (NULL != hex) {
79         rtinfo("%s\t%s", msg, hex);
80         rtdealloc(hex);
81     }
82 }
83 
84 size_t
d_binptr_to_pos(const uint8_t * const ptr,const uint8_t * const end,size_t size)85 d_binptr_to_pos(const uint8_t * const ptr, const uint8_t * const end, size_t size) {
86     assert(NULL != ptr && NULL != end);
87 
88     return (size - (end - ptr));
89 }
90 
91 #endif /* if POSTGIS_DEBUG_LEVEL > 2 */
92 
93 
94 #ifdef OPTIMIZE_SPACE
95 
96 /*
97  * Set given number of bits of the given byte,
98  * starting from given bitOffset (from the first)
99  * to the given value.
100  *
101  * Examples:
102  *   char ch;
103  *   ch=0; setBits(&ch, 1, 1, 0) -> ch==8
104  *   ch=0; setBits(&ch, 3, 2, 1) -> ch==96 (0x60)
105  *
106  * Note that number of bits set must be <= 8-bitOffset
107  *
108  */
109 void
setBits(char * ch,double val,int bits,int bitOffset)110 setBits(char* ch, double val, int bits, int bitOffset) {
111     char mask = 0xFF >> (8 - bits);
112     char ival = val;
113 
114 
115 		assert(ch != NULL);
116     assert(8 - bitOffset >= bits);
117 
118     RASTER_DEBUGF(4, "ival:%d bits:%d mask:%hhx bitoffset:%d\n",
119             ival, bits, mask, bitOffset);
120 
121     /* clear all but significant bits from ival */
122     ival &= mask;
123 #if POSTGIS_RASTER_WARN_ON_TRUNCATION > 0
124     if (ival != val) {
125         rtwarn("Pixel value for %d-bits band got truncated"
126                 " from %g to %hhu", bits, val, ival);
127     }
128 #endif /* POSTGIS_RASTER_WARN_ON_TRUNCATION */
129 
130     RASTER_DEBUGF(4, " cleared ival:%hhx\n", ival);
131 
132 
133     /* Shift ival so the significant bits start at
134      * the first bit */
135     ival <<= (8 - bitOffset - bits);
136 
137     RASTER_DEBUGF(4, " ival shifted:%hhx\n", ival);
138     RASTER_DEBUGF(4, "  ch:%hhx\n", *ch);
139 
140     /* clear first bits of target */
141     *ch &= ~(mask << (8 - bits - bitOffset));
142 
143     RASTER_DEBUGF(4, "  ch cleared:%hhx\n", *ch);
144 
145     /* Set the first bit of target */
146     *ch |= ival;
147 
148     RASTER_DEBUGF(4, "  ch ored:%hhx\n", *ch);
149 
150 }
151 #endif /* OPTIMIZE_SPACE */
152 
153 void
swap_char(uint8_t * a,uint8_t * b)154 swap_char(uint8_t *a, uint8_t *b) {
155     uint8_t c = 0;
156 
157     assert(NULL != a && NULL != b);
158 
159     c = *a;
160     *a = *b;
161     *b = c;
162 }
163 
164 void
flip_endian_16(uint8_t * d)165 flip_endian_16(uint8_t *d) {
166     assert(NULL != d);
167 
168     swap_char(d, d + 1);
169 }
170 
171 void
flip_endian_32(uint8_t * d)172 flip_endian_32(uint8_t *d) {
173     assert(NULL != d);
174 
175     swap_char(d, d + 3);
176     swap_char(d + 1, d + 2);
177 }
178 
179 void
flip_endian_64(uint8_t * d)180 flip_endian_64(uint8_t *d) {
181     assert(NULL != d);
182 
183     swap_char(d + 7, d);
184     swap_char(d + 6, d + 1);
185     swap_char(d + 5, d + 2);
186     swap_char(d + 4, d + 3);
187 }
188 
189 uint8_t
isMachineLittleEndian(void)190 isMachineLittleEndian(void) {
191     static int endian_check_int = 1; /* dont modify this!!! */
192     /* 0=big endian|xdr --  1=little endian|ndr */
193     return *((uint8_t *) & endian_check_int);
194 }
195 
196 uint8_t
read_uint8(const uint8_t ** from)197 read_uint8(const uint8_t** from) {
198     assert(NULL != from);
199 
200     return *(*from)++;
201 }
202 
203 /* unused up to now
204 void
205 write_uint8(uint8_t** from, uint8_t v) {
206     assert(NULL != from);
207 
208  *(*from)++ = v;
209 }
210 */
211 
212 int8_t
read_int8(const uint8_t ** from)213 read_int8(const uint8_t** from) {
214     assert(NULL != from);
215 
216     return (int8_t) read_uint8(from);
217 }
218 
219 /* unused up to now
220 void
221 write_int8(uint8_t** from, int8_t v) {
222     assert(NULL != from);
223 
224  *(*from)++ = v;
225 }
226 */
227 
228 uint16_t
read_uint16(const uint8_t ** from,uint8_t littleEndian)229 read_uint16(const uint8_t** from, uint8_t littleEndian) {
230     uint16_t ret = 0;
231 
232     assert(NULL != from);
233 
234     if (littleEndian) {
235         ret = (*from)[0] |
236                 (*from)[1] << 8;
237     } else {
238         /* big endian */
239         ret = (*from)[0] << 8 |
240                 (*from)[1];
241     }
242     *from += 2;
243     return ret;
244 }
245 
246 void
write_uint16(uint8_t ** to,uint8_t littleEndian,uint16_t v)247 write_uint16(uint8_t** to, uint8_t littleEndian, uint16_t v) {
248     assert(NULL != to);
249 
250     if (littleEndian) {
251         (*to)[0] = v & 0x00FF;
252         (*to)[1] = v >> 8;
253     } else {
254         (*to)[1] = v & 0x00FF;
255         (*to)[0] = v >> 8;
256     }
257     *to += 2;
258 }
259 
260 int16_t
read_int16(const uint8_t ** from,uint8_t littleEndian)261 read_int16(const uint8_t** from, uint8_t littleEndian) {
262     assert(NULL != from);
263 
264     return (int16_t)read_uint16(from, littleEndian);
265 }
266 
267 /* unused up to now
268 void
269 write_int16(uint8_t** to, uint8_t littleEndian, int16_t v) {
270     assert(NULL != to);
271 
272     if ( littleEndian )
273     {
274         (*to)[0] = v & 0x00FF;
275         (*to)[1] = v >> 8;
276     }
277     else
278     {
279         (*to)[1] = v & 0x00FF;
280         (*to)[0] = v >> 8;
281     }
282  *to += 2;
283 }
284 */
285 
286 uint32_t
read_uint32(const uint8_t ** from,uint8_t littleEndian)287 read_uint32(const uint8_t** from, uint8_t littleEndian) {
288     uint32_t ret = 0;
289 
290     assert(NULL != from);
291 
292     if (littleEndian) {
293         ret = (uint32_t) ((*from)[0] & 0xff) |
294                 (uint32_t) ((*from)[1] & 0xff) << 8 |
295                 (uint32_t) ((*from)[2] & 0xff) << 16 |
296                 (uint32_t) ((*from)[3] & 0xff) << 24;
297     } else {
298         /* big endian */
299         ret = (uint32_t) ((*from)[3] & 0xff) |
300                 (uint32_t) ((*from)[2] & 0xff) << 8 |
301                 (uint32_t) ((*from)[1] & 0xff) << 16 |
302                 (uint32_t) ((*from)[0] & 0xff) << 24;
303     }
304 
305     *from += 4;
306     return ret;
307 }
308 
309 /* unused up to now
310 void
311 write_uint32(uint8_t** to, uint8_t littleEndian, uint32_t v) {
312     assert(NULL != to);
313 
314     if ( littleEndian )
315     {
316         (*to)[0] = v & 0x000000FF;
317         (*to)[1] = ( v & 0x0000FF00 ) >> 8;
318         (*to)[2] = ( v & 0x00FF0000 ) >> 16;
319         (*to)[3] = ( v & 0xFF000000 ) >> 24;
320     }
321     else
322     {
323         (*to)[3] = v & 0x000000FF;
324         (*to)[2] = ( v & 0x0000FF00 ) >> 8;
325         (*to)[1] = ( v & 0x00FF0000 ) >> 16;
326         (*to)[0] = ( v & 0xFF000000 ) >> 24;
327     }
328  *to += 4;
329 }
330 */
331 
332 int32_t
read_int32(const uint8_t ** from,uint8_t littleEndian)333 read_int32(const uint8_t** from, uint8_t littleEndian) {
334     assert(NULL != from);
335 
336     return (int32_t)read_uint32(from, littleEndian);
337 }
338 
339 /* unused up to now
340 void
341 write_int32(uint8_t** to, uint8_t littleEndian, int32_t v) {
342     assert(NULL != to);
343 
344     if ( littleEndian )
345     {
346         (*to)[0] = v & 0x000000FF;
347         (*to)[1] = ( v & 0x0000FF00 ) >> 8;
348         (*to)[2] = ( v & 0x00FF0000 ) >> 16;
349         (*to)[3] = ( v & 0xFF000000 ) >> 24;
350     }
351     else
352     {
353         (*to)[3] = v & 0x000000FF;
354         (*to)[2] = ( v & 0x0000FF00 ) >> 8;
355         (*to)[1] = ( v & 0x00FF0000 ) >> 16;
356         (*to)[0] = ( v & 0xFF000000 ) >> 24;
357     }
358  *to += 4;
359 }
360 */
361 
362 float
read_float32(const uint8_t ** from,uint8_t littleEndian)363 read_float32(const uint8_t** from, uint8_t littleEndian) {
364 
365     union {
366         float f;
367         uint32_t i;
368     } ret;
369 
370     ret.i = read_uint32(from, littleEndian);
371 
372     return ret.f;
373 }
374 
375 /* unused up to now
376 void
377 write_float32(uint8_t** from, uint8_t littleEndian, float f) {
378     union {
379         float f;
380         uint32_t i;
381     } u;
382 
383     u.f = f;
384     write_uint32(from, littleEndian, u.i);
385 }
386 */
387 
388 double
read_float64(const uint8_t ** from,uint8_t littleEndian)389 read_float64(const uint8_t** from, uint8_t littleEndian) {
390 
391     union {
392         double d;
393         uint64_t i;
394     } ret;
395 
396     assert(NULL != from);
397 
398     if (littleEndian) {
399         ret.i = (uint64_t) ((*from)[0] & 0xff) |
400                 (uint64_t) ((*from)[1] & 0xff) << 8 |
401                 (uint64_t) ((*from)[2] & 0xff) << 16 |
402                 (uint64_t) ((*from)[3] & 0xff) << 24 |
403                 (uint64_t) ((*from)[4] & 0xff) << 32 |
404                 (uint64_t) ((*from)[5] & 0xff) << 40 |
405                 (uint64_t) ((*from)[6] & 0xff) << 48 |
406                 (uint64_t) ((*from)[7] & 0xff) << 56;
407     } else {
408         /* big endian */
409         ret.i = (uint64_t) ((*from)[7] & 0xff) |
410                 (uint64_t) ((*from)[6] & 0xff) << 8 |
411                 (uint64_t) ((*from)[5] & 0xff) << 16 |
412                 (uint64_t) ((*from)[4] & 0xff) << 24 |
413                 (uint64_t) ((*from)[3] & 0xff) << 32 |
414                 (uint64_t) ((*from)[2] & 0xff) << 40 |
415                 (uint64_t) ((*from)[1] & 0xff) << 48 |
416                 (uint64_t) ((*from)[0] & 0xff) << 56;
417     }
418 
419     *from += 8;
420     return ret.d;
421 }
422 
423 /* unused up to now
424 void
425 write_float64(uint8_t** to, uint8_t littleEndian, double v) {
426     union {
427         double d;
428         uint64_t i;
429     } u;
430 
431     assert(NULL != to);
432 
433     u.d = v;
434 
435     if ( littleEndian )
436     {
437         (*to)[0] =   u.i & 0x00000000000000FFULL;
438         (*to)[1] = ( u.i & 0x000000000000FF00ULL ) >> 8;
439         (*to)[2] = ( u.i & 0x0000000000FF0000ULL ) >> 16;
440         (*to)[3] = ( u.i & 0x00000000FF000000ULL ) >> 24;
441         (*to)[4] = ( u.i & 0x000000FF00000000ULL ) >> 32;
442         (*to)[5] = ( u.i & 0x0000FF0000000000ULL ) >> 40;
443         (*to)[6] = ( u.i & 0x00FF000000000000ULL ) >> 48;
444         (*to)[7] = ( u.i & 0xFF00000000000000ULL ) >> 56;
445     }
446     else
447     {
448         (*to)[7] =   u.i & 0x00000000000000FFULL;
449         (*to)[6] = ( u.i & 0x000000000000FF00ULL ) >> 8;
450         (*to)[5] = ( u.i & 0x0000000000FF0000ULL ) >> 16;
451         (*to)[4] = ( u.i & 0x00000000FF000000ULL ) >> 24;
452         (*to)[3] = ( u.i & 0x000000FF00000000ULL ) >> 32;
453         (*to)[2] = ( u.i & 0x0000FF0000000000ULL ) >> 40;
454         (*to)[1] = ( u.i & 0x00FF000000000000ULL ) >> 48;
455         (*to)[0] = ( u.i & 0xFF00000000000000ULL ) >> 56;
456     }
457  *to += 8;
458 }
459 */
460 
461 static uint32_t
rt_raster_serialized_size(rt_raster raster)462 rt_raster_serialized_size(rt_raster raster) {
463 	uint32_t size = sizeof (struct rt_raster_serialized_t);
464 	uint16_t i = 0;
465 
466 	assert(NULL != raster);
467 
468 	RASTER_DEBUGF(3, "Serialized size with just header:%d - now adding size of %d bands",
469 		size, raster->numBands);
470 
471 	for (i = 0; i < raster->numBands; ++i) {
472 		rt_band band = raster->bands[i];
473 		rt_pixtype pixtype = band->pixtype;
474 		int pixbytes = rt_pixtype_size(pixtype);
475 
476 		if (pixbytes < 1) {
477 			rterror("rt_raster_serialized_size: Corrupted band: unknown pixtype");
478 			return 0;
479 		}
480 
481 		/* Add space for band type, hasnodata flag and data padding */
482 		size += pixbytes;
483 
484 		/* Add space for nodata value */
485 		size += pixbytes;
486 
487 		if (band->offline) {
488 			/* Add space for band number */
489 			size += 1;
490 
491 			/* Add space for null-terminated path */
492 			size += strlen(band->data.offline.path) + 1;
493 		}
494 		else {
495 			/* Add space for raster band data */
496 			size += pixbytes * raster->width * raster->height;
497 		}
498 
499 		RASTER_DEBUGF(3, "Size before alignment is %d", size);
500 
501 		/* Align size to 8-bytes boundary (trailing padding) */
502 		/* XXX jorgearevalo: bug here. If the size is actually 8-bytes aligned,
503 		   this line will add 8 bytes trailing padding, and it's not necessary */
504 		/*size += 8 - (size % 8);*/
505 		if (size % 8)
506 			size += 8 - (size % 8);
507 
508 		RASTER_DEBUGF(3, "Size after alignment is %d", size);
509 	}
510 
511 	return size;
512 }
513 
514 /**
515  * Return this raster in serialized form.
516  * Memory (band data included) is copied from rt_raster.
517  *
518  * Serialized form is documented in doc/RFC1-SerializedFormat.
519  */
520 void*
rt_raster_serialize(rt_raster raster)521 rt_raster_serialize(rt_raster raster) {
522 	uint32_t size = 0;
523 	uint8_t* ret = NULL;
524 	uint8_t* ptr = NULL;
525 	uint16_t i = 0;
526 
527 	assert(NULL != raster);
528 
529 	size = rt_raster_serialized_size(raster);
530 	ret = (uint8_t*) rtalloc(size);
531 	if (!ret) {
532 		rterror("rt_raster_serialize: Out of memory allocating %d bytes for serializing a raster", size);
533 		return NULL;
534 	}
535 	memset(ret, '-', size);
536 	ptr = ret;
537 
538 	RASTER_DEBUGF(3, "sizeof(struct rt_raster_serialized_t):%u",
539 		sizeof (struct rt_raster_serialized_t));
540 	RASTER_DEBUGF(3, "sizeof(struct rt_raster_t):%u",
541 		sizeof (struct rt_raster_t));
542 	RASTER_DEBUGF(3, "serialized size:%lu", (long unsigned) size);
543 
544 	/* Set size */
545 	/* NOTE: Value of rt_raster.size may be updated in
546 	 * returned object, for instance, by rt_pg layer to
547 	 * store value calculated by SET_VARSIZE.
548 	 */
549 	raster->size = size;
550 
551 	/* Set version */
552 	raster->version = 0;
553 
554 	/* Copy header */
555 	memcpy(ptr, raster, sizeof (struct rt_raster_serialized_t));
556 
557 	RASTER_DEBUG(3, "Start hex dump of raster being serialized using 0x2D to mark non-written bytes");
558 
559 #if POSTGIS_DEBUG_LEVEL > 2
560 	uint8_t* dbg_ptr = ptr;
561 	d_print_binary_hex("HEADER", dbg_ptr, size);
562 #endif
563 
564 	ptr += sizeof (struct rt_raster_serialized_t);
565 
566 	/* Serialize bands now */
567 	for (i = 0; i < raster->numBands; ++i) {
568 		rt_band band = raster->bands[i];
569 		assert(NULL != band);
570 
571 		rt_pixtype pixtype = band->pixtype;
572 		int pixbytes = rt_pixtype_size(pixtype);
573 		if (pixbytes < 1) {
574 			rterror("rt_raster_serialize: Corrupted band: unknown pixtype");
575 			rtdealloc(ret);
576 			return NULL;
577 		}
578 
579 		/* Add band type */
580 		*ptr = band->pixtype;
581 		if (band->offline) {
582 #ifdef POSTGIS_RASTER_DISABLE_OFFLINE
583       rterror("rt_raster_serialize: offdb raster support disabled at compile-time");
584       return NULL;
585 #endif
586 			*ptr |= BANDTYPE_FLAG_OFFDB;
587 		}
588 		if (band->hasnodata) {
589 			*ptr |= BANDTYPE_FLAG_HASNODATA;
590 		}
591 
592 		if (band->isnodata) {
593 			*ptr |= BANDTYPE_FLAG_ISNODATA;
594 		}
595 
596 #if POSTGIS_DEBUG_LEVEL > 2
597 		d_print_binary_hex("PIXTYPE", dbg_ptr, size);
598 #endif
599 
600 		ptr += 1;
601 
602 		/* Add padding (if needed) */
603 		if (pixbytes > 1) {
604 			memset(ptr, '\0', pixbytes - 1);
605 			ptr += pixbytes - 1;
606 		}
607 
608 #if POSTGIS_DEBUG_LEVEL > 2
609 		d_print_binary_hex("PADDING", dbg_ptr, size);
610 #endif
611 
612 		/* Consistency checking (ptr is pixbytes-aligned) */
613 		assert(!((ptr - ret) % pixbytes));
614 
615 		/* Add nodata value */
616 		switch (pixtype) {
617 			case PT_1BB:
618 			case PT_2BUI:
619 			case PT_4BUI:
620 			case PT_8BUI: {
621 				uint8_t v = band->nodataval;
622 				*ptr = v;
623 				ptr += 1;
624 				break;
625 			}
626 			case PT_8BSI: {
627 				int8_t v = band->nodataval;
628 				*ptr = (uint8_t)v;
629 				ptr += 1;
630 				break;
631 			}
632 			case PT_16BSI: {
633 				int16_t v = band->nodataval;
634 				memcpy(ptr, &v, 2);
635 				ptr += 2;
636 				break;
637 			}
638 			case PT_16BUI: {
639 				uint16_t v = band->nodataval;
640 				memcpy(ptr, &v, 2);
641 				ptr += 2;
642 				break;
643 			}
644 			case PT_32BSI: {
645 				int32_t v = band->nodataval;
646 				memcpy(ptr, &v, 4);
647 				ptr += 4;
648 				break;
649 			}
650 			case PT_32BUI: {
651 				uint32_t v = band->nodataval;
652 				memcpy(ptr, &v, 4);
653 				ptr += 4;
654 				break;
655 			}
656 			case PT_32BF: {
657 				float v = band->nodataval;
658 				memcpy(ptr, &v, 4);
659 				ptr += 4;
660 				break;
661 			}
662 			case PT_64BF: {
663 				memcpy(ptr, &band->nodataval, 8);
664 				ptr += 8;
665 				break;
666 			}
667 			default:
668 				rterror("rt_raster_serialize: Fatal error caused by unknown pixel type. Aborting.");
669 				rtdealloc(ret);
670 				return NULL;
671 		}
672 
673 		/* Consistency checking (ptr is pixbytes-aligned) */
674 		assert(!((ptr - ret) % pixbytes));
675 
676 #if POSTGIS_DEBUG_LEVEL > 2
677 		d_print_binary_hex("nodata", dbg_ptr, size);
678 #endif
679 
680 		if (band->offline) {
681 			/* Write band number */
682 			*ptr = band->data.offline.bandNum;
683 			ptr += 1;
684 
685 			/* Write path */
686 			strcpy((char*) ptr, band->data.offline.path);
687 			ptr += strlen(band->data.offline.path) + 1;
688 		}
689 		else {
690 			/* Write data */
691 			uint32_t datasize = raster->width * raster->height * pixbytes;
692 			memcpy(ptr, band->data.mem, datasize);
693 			ptr += datasize;
694 		}
695 
696 #if POSTGIS_DEBUG_LEVEL > 2
697 		d_print_binary_hex("BAND", dbg_ptr, size);
698 #endif
699 
700 		/* Pad up to 8-bytes boundary */
701 		while ((ptr-ret) % 8) {
702 			*ptr = 0;
703 			++ptr;
704 		}
705 
706 		/* Consistency checking (ptr is pixbytes-aligned) */
707 		assert(!((ptr - ret) % pixbytes));
708 	} /* for-loop over bands */
709 
710 #if POSTGIS_DEBUG_LEVEL > 2
711 		d_print_binary_hex("SERIALIZED RASTER", dbg_ptr, size);
712 #endif
713 	return ret;
714 }
715 
716 /**
717  * Return a raster from a serialized form.
718  *
719  * Serialized form is documented in doc/RFC1-SerializedFormat.
720  *
721  * NOTE: the raster will contain pointer to the serialized
722  * form (including band data), which must be kept alive.
723  */
724 rt_raster
rt_raster_deserialize(void * serialized,int header_only)725 rt_raster_deserialize(void* serialized, int header_only) {
726 	rt_raster rast = NULL;
727 	const uint8_t *ptr = NULL;
728 	const uint8_t *beg = NULL;
729 	uint16_t i = 0;
730 	uint16_t j = 0;
731 #ifdef WORDS_BIGENDIAN
732 	uint8_t littleEndian = LW_FALSE;
733 #else
734 	uint8_t littleEndian = LW_TRUE;
735 #endif
736 
737 	assert(NULL != serialized);
738 
739 	RASTER_DEBUG(2, "rt_raster_deserialize: Entering...");
740 
741 	/* NOTE: Value of rt_raster.size may be different
742 	 * than actual size of raster data being read.
743 	 * See note on SET_VARSIZE in rt_raster_serialize function above.
744 	 */
745 
746 	/* Allocate memory for deserialized raster header */
747 	RASTER_DEBUG(3, "rt_raster_deserialize: Allocating memory for deserialized raster header");
748 	rast = (rt_raster) rtalloc(sizeof (struct rt_raster_t));
749 	if (!rast) {
750 		rterror("rt_raster_deserialize: Out of memory allocating raster for deserialization");
751 		return NULL;
752 	}
753 
754 	/* Deserialize raster header */
755 	RASTER_DEBUG(3, "rt_raster_deserialize: Deserialize raster header");
756 	memcpy(rast, serialized, sizeof (struct rt_raster_serialized_t));
757 
758 	if (0 == rast->numBands || header_only) {
759 		rast->bands = 0;
760 		return rast;
761 	}
762 
763 	beg = (const uint8_t*) serialized;
764 
765 	/* Allocate registry of raster bands */
766 	RASTER_DEBUG(3, "rt_raster_deserialize: Allocating memory for bands");
767 	rast->bands = rtalloc(rast->numBands * sizeof (rt_band));
768 	if (rast->bands == NULL) {
769 		rterror("rt_raster_deserialize: Out of memory allocating bands");
770 		rtdealloc(rast);
771 		return NULL;
772 	}
773 
774 	RASTER_DEBUGF(3, "rt_raster_deserialize: %d bands", rast->numBands);
775 
776 	/* Move to the beginning of first band */
777 	ptr = beg;
778 	ptr += sizeof (struct rt_raster_serialized_t);
779 
780 	/* Deserialize bands now */
781 	for (i = 0; i < rast->numBands; ++i) {
782 		rt_band band = NULL;
783 		uint8_t type = 0;
784 		int pixbytes = 0;
785 
786 		band = rtalloc(sizeof(struct rt_band_t));
787 		if (!band) {
788 			rterror("rt_raster_deserialize: Out of memory allocating rt_band during deserialization");
789 			for (j = 0; j < i; j++) rt_band_destroy(rast->bands[j]);
790 			rt_raster_destroy(rast);
791 			return NULL;
792 		}
793 
794 		rast->bands[i] = band;
795 
796 		type = *ptr;
797 		ptr++;
798 		band->pixtype = type & BANDTYPE_PIXTYPE_MASK;
799 
800 		RASTER_DEBUGF(3, "rt_raster_deserialize: band %d with pixel type %s", i, rt_pixtype_name(band->pixtype));
801 
802 		band->offline = BANDTYPE_IS_OFFDB(type) ? 1 : 0;
803 		band->hasnodata = BANDTYPE_HAS_NODATA(type) ? 1 : 0;
804 		band->isnodata = band->hasnodata ? (BANDTYPE_IS_NODATA(type) ? 1 : 0) : 0;
805 		band->width = rast->width;
806 		band->height = rast->height;
807 		band->ownsdata = 0; /* we do NOT own this data!!! */
808 		band->raster = rast;
809 
810 		/* Advance by data padding */
811 		pixbytes = rt_pixtype_size(band->pixtype);
812 		ptr += pixbytes - 1;
813 
814 		/* Read nodata value */
815 		switch (band->pixtype) {
816 			case PT_1BB: {
817 				band->nodataval = ((int) read_uint8(&ptr)) & 0x01;
818 				break;
819 			}
820 			case PT_2BUI: {
821 				band->nodataval = ((int) read_uint8(&ptr)) & 0x03;
822 				break;
823 			}
824 			case PT_4BUI: {
825 				band->nodataval = ((int) read_uint8(&ptr)) & 0x0F;
826 				break;
827 			}
828 			case PT_8BSI: {
829 				band->nodataval = read_int8(&ptr);
830 				break;
831 			}
832 			case PT_8BUI: {
833 				band->nodataval = read_uint8(&ptr);
834 				break;
835 			}
836 			case PT_16BSI: {
837 				band->nodataval = read_int16(&ptr, littleEndian);
838 				break;
839 			}
840 			case PT_16BUI: {
841 				band->nodataval = read_uint16(&ptr, littleEndian);
842 				break;
843 			}
844 			case PT_32BSI: {
845 				band->nodataval = read_int32(&ptr, littleEndian);
846 				break;
847 			}
848 			case PT_32BUI: {
849 				band->nodataval = read_uint32(&ptr, littleEndian);
850 				break;
851 			}
852 			case PT_32BF: {
853 				band->nodataval = read_float32(&ptr, littleEndian);
854 				break;
855 			}
856 			case PT_64BF: {
857 				band->nodataval = read_float64(&ptr, littleEndian);
858 				break;
859 			}
860 			default: {
861 				rterror("rt_raster_deserialize: Unknown pixeltype %d", band->pixtype);
862 				for (j = 0; j <= i; j++) rt_band_destroy(rast->bands[j]);
863 				rt_raster_destroy(rast);
864 				return NULL;
865 			}
866 		}
867 
868 		RASTER_DEBUGF(3, "rt_raster_deserialize: has nodata flag %d", band->hasnodata);
869 		RASTER_DEBUGF(3, "rt_raster_deserialize: nodata value %g", band->nodataval);
870 
871 		/* Consistency checking (ptr is pixbytes-aligned) */
872 		assert(!((ptr - beg) % pixbytes));
873 
874 		if (band->offline) {
875 			int pathlen = 0;
876 
877 			/* Read band number */
878 			band->data.offline.bandNum = *ptr;
879 			ptr += 1;
880 
881 			/* Register path */
882 			pathlen = strlen((char*) ptr);
883 			band->data.offline.path = rtalloc(sizeof(char) * (pathlen + 1));
884 			if (band->data.offline.path == NULL) {
885 				rterror("rt_raster_deserialize: Could not allocate memory for offline band path");
886 				for (j = 0; j <= i; j++) rt_band_destroy(rast->bands[j]);
887 				rt_raster_destroy(rast);
888 				return NULL;
889 			}
890 
891 			memcpy(band->data.offline.path, ptr, pathlen);
892 			band->data.offline.path[pathlen] = '\0';
893 			ptr += pathlen + 1;
894 
895 			band->data.offline.mem = NULL;
896 		}
897 		else {
898 			/* Register data */
899 			const uint32_t datasize = rast->width * rast->height * pixbytes;
900 			band->data.mem = (uint8_t*) ptr;
901 			ptr += datasize;
902 		}
903 
904 		/* Skip bytes of padding up to 8-bytes boundary */
905 #if POSTGIS_DEBUG_LEVEL > 0
906 		const uint8_t *padbeg = ptr;
907 #endif
908 		while (0 != ((ptr - beg) % 8)) {
909 			++ptr;
910 		}
911 
912 		RASTER_DEBUGF(3, "rt_raster_deserialize: skip %d bytes of 8-bytes boundary padding", ptr - padbeg);
913 
914 		/* Consistency checking (ptr is pixbytes-aligned) */
915 		assert(!((ptr - beg) % pixbytes));
916 	}
917 
918 	return rast;
919 }
920