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