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