1 : /******************************************************************************
2 : * File : wktrasterwrapper.cpp
3 : * Project: WKT Raster driver
4 : * Purpose: Implementation of a wrapper around the WKTRaster and its bands
5 : * Author: Jorge Arevalo, jorgearevalo@gis4free.org
6 : *
7 : * Last changes: $Id: wktrasterwrapper.cpp 18163 2009-12-03 17:47:38Z jorgearevalo $
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2009, Jorge Arevalo, jorgearevalo@gis4free.org
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ******************************************************************************/
30 : #include "wktraster.h"
31 :
32 : CPL_CVSID("$Id: wktrasterwrapper.cpp 18163 2009-12-03 17:47:38Z jorgearevalo $");
33 :
34 : /************************************************************************
35 : * ====================================================================
36 : * WKTRasterWrapper
37 : * ====================================================================
38 : *
39 : * This class wraps the HEXWKB representation of a PostGIS WKT Raster.
40 : *
41 : * It splits the hexwkb string into fields, and reconstructs this string
42 : * from the fields each time that the representation is required (see
43 : * GetBinaryRepresentation method).
44 : *
45 : * The best way to get the representation of the raster is by using the
46 : * GetBinaryRepresentation and GetHexWkbRepresentation methods. This
47 : * methods construct the representation based on the class properties.
48 : *
49 : * If you access the pszHexWkb or pbyHexWkb variables directly, you may
50 : * get a non-updated version of the raster. Anyway, you only can access
51 : * this variables from friend classes.
52 : *
53 : * TODO:
54 : * - Check assertions that sometimes fail (in several places of the code):
55 : * CPLAssert(nTransformedBytes == nLengthByWkbString)
56 : * - Check that there is enough data in buffer (method Initialize)
57 : * - FIXME: dfNoDataValue is a double. Doesn't make sense to fetch less than 8 bytes
58 : * if 1 byte, should be put into a Byte and then casted to a double,
59 : * if 2 bytes, should be put into a Int16/UInt16 and then casted to a double, etc...
60 : * - Modify GetWktExtent method to accept non-regular blocking
61 : ************************************************************************/
62 :
63 : /**
64 : * Class constructor.
65 : */
66 0 : WKTRasterWrapper::WKTRasterWrapper() {
67 0 : papoBands = NULL;
68 0 : pszHexWkb = NULL;
69 0 : pbyHexWkb = NULL;
70 0 : pszWktExtent = NULL;
71 0 : }
72 :
73 : /**
74 : * Fill all the raster properties with the string
75 : * hexwkb representation given as input.
76 : * This method swaps words if the raster endianess is distinct from
77 : * the machine endianess
78 : * Properties:
79 : * const char *: the string hexwkb representation of the raster
80 : */
81 0 : int WKTRasterWrapper::Initialize(const char* pszHex) {
82 0 : int nBufferDataWithoutHeaderLen = 0;
83 0 : int nRasterHeaderLen = 0;
84 0 : int nRasterBandHeaderLen = 0;
85 0 : int nRasterDataLen = 0;
86 : GByte * pbyAuxPtr;
87 0 : GByte byMachineEndianess = NDR; // by default
88 :
89 : // Check machine endianess
90 : #ifdef CPL_LSB
91 0 : byMachineEndianess = NDR;
92 : #else
93 : byMachineEndianess = XDR;
94 : #endif
95 :
96 : /*************************************************************************
97 : * Check parameters
98 : *************************************************************************/
99 0 : if (pszHex == NULL || strlen(pszHex) % 2) {
100 : CPLError(CE_Failure, CPLE_NotSupported,
101 0 : "Couldn't create raster wrapper, invalid raster hexwkb string");
102 0 : return FALSE;
103 : }
104 :
105 : /*************************************************************************
106 : * Check if raster has enough data
107 : *************************************************************************/
108 : nRasterHeaderLen =
109 : sizeof (GByte) +
110 : 4 * sizeof (GUInt16) +
111 : sizeof (GInt32) +
112 0 : 6 * sizeof (double);
113 :
114 : nBufferDataWithoutHeaderLen =
115 0 : strlen(pszHex +2*nRasterHeaderLen) / 2;
116 :
117 0 : pbyHexWkb = CPLHexToBinary(pszHex, &nLengthByWkbString);
118 :
119 0 : if (nRasterHeaderLen > nLengthByWkbString ||
120 : nLengthByWkbString != nRasterHeaderLen + nBufferDataWithoutHeaderLen)
121 : {
122 : CPLError(CE_Failure, CPLE_ObjectNull,
123 0 : "Raster object is corrupted, not enough data");
124 0 : return FALSE;
125 : }
126 :
127 :
128 : /*************************************************************************
129 : * Copy raster as class attribute, and transform it to binary
130 : *************************************************************************/
131 0 : nLengthHexWkbString = strlen(pszHex);
132 :
133 0 : pszHexWkb = (char *) VSIMalloc(nLengthHexWkbString);
134 0 : if (pszHexWkb == NULL) {
135 : CPLError(CE_Failure, CPLE_ObjectNull,
136 0 : "Couldn't allocate memory for raster wrapper, aborting");
137 0 : return FALSE;
138 : }
139 :
140 0 : memcpy(pszHexWkb, pszHex, nLengthHexWkbString * sizeof (GByte));
141 :
142 :
143 : /***********************************************************************
144 : * Get endianess. This is important, because we could need to swap
145 : * words if the data endianess is distinct from machine endianess
146 : ***********************************************************************/
147 0 : memcpy(&byEndianess, pbyHexWkb, sizeof(GByte));
148 :
149 : // We are going to use this pointer to move over the string
150 0 : pbyAuxPtr = pbyHexWkb + sizeof (GByte);
151 :
152 : /*************************************************************************
153 : * Parse HexWkb string in binary format and fill the rest of class fields
154 : *************************************************************************/
155 0 : memcpy(&nVersion, pbyAuxPtr, sizeof (GUInt16));
156 0 : if (byEndianess != byMachineEndianess)
157 0 : GDALSwapWords(&nVersion, sizeof (GUInt16), 1, sizeof (GUInt16));
158 0 : pbyAuxPtr += sizeof (GUInt16);
159 :
160 :
161 : /**
162 : * Check WKT Raster version
163 : */
164 0 : if (nVersion != WKT_RASTER_VERSION) {
165 : CPLError(CE_Failure, CPLE_NotSupported,
166 : "WKT Raster version not supported (%d). Supported raster\
167 0 : version is %d\n", nVersion, WKT_RASTER_VERSION);
168 :
169 0 : return FALSE;
170 : }
171 :
172 :
173 0 : memcpy(&nBands, pbyAuxPtr, sizeof (GUInt16));
174 0 : if (byEndianess != byMachineEndianess)
175 0 : GDALSwapWords(&nBands, sizeof (GUInt16), 1, sizeof (GUInt16));
176 0 : pbyAuxPtr += sizeof (GUInt16);
177 :
178 0 : memcpy(&dfScaleX, pbyAuxPtr, sizeof (double));
179 0 : if (byEndianess != byMachineEndianess)
180 0 : GDALSwapWords(&dfScaleX, sizeof (double), 1, sizeof (double));
181 0 : pbyAuxPtr += sizeof (double);
182 :
183 0 : memcpy(&dfScaleY, pbyAuxPtr, sizeof (double));
184 0 : if (byEndianess != byMachineEndianess)
185 0 : GDALSwapWords(&dfScaleY, sizeof (double), 1, sizeof (double));
186 0 : pbyAuxPtr += sizeof (double);
187 :
188 0 : memcpy(&dfIpX, pbyAuxPtr, sizeof (double));
189 0 : if (byEndianess != byMachineEndianess)
190 0 : GDALSwapWords(&dfIpX, sizeof (double), 1, sizeof (double));
191 0 : pbyAuxPtr += sizeof (double);
192 :
193 0 : memcpy(&dfIpY, pbyAuxPtr, sizeof (double));
194 0 : if (byEndianess != byMachineEndianess)
195 0 : GDALSwapWords(&dfIpY, sizeof (double), 1, sizeof (double));
196 0 : pbyAuxPtr += sizeof (double);
197 :
198 0 : memcpy(&dfSkewX, pbyAuxPtr, sizeof (double));
199 0 : if (byEndianess != byMachineEndianess)
200 0 : GDALSwapWords(&dfSkewX, sizeof (double), 1, sizeof (double));
201 0 : pbyAuxPtr += sizeof (double);
202 :
203 0 : memcpy(&dfSkewY, pbyAuxPtr, sizeof (double));
204 0 : if (byEndianess != byMachineEndianess)
205 0 : GDALSwapWords(&dfSkewY, sizeof (double), 1, sizeof (double));
206 0 : pbyAuxPtr += sizeof (double);
207 :
208 0 : memcpy(&nSrid, pbyAuxPtr, sizeof (GInt32));
209 0 : if (byEndianess != byMachineEndianess)
210 0 : GDALSwapWords(&nSrid, sizeof (GInt32), 1, sizeof (GInt32));
211 0 : pbyAuxPtr += sizeof (GInt32);
212 :
213 0 : memcpy(&nWidth, pbyAuxPtr, sizeof (GUInt16));
214 0 : if (byEndianess != byMachineEndianess)
215 0 : GDALSwapWords(&nWidth, sizeof (GUInt16), 1, sizeof (GUInt16));
216 0 : pbyAuxPtr += sizeof (GUInt16);
217 :
218 0 : memcpy(&nHeight, pbyAuxPtr, sizeof (GUInt16));
219 0 : if (byEndianess != byMachineEndianess)
220 0 : GDALSwapWords(&nHeight, sizeof (GUInt16), 1, sizeof (GUInt16));
221 0 : pbyAuxPtr += sizeof (GUInt16);
222 :
223 : // Allocate memory for bands
224 : papoBands = (WKTRasterBandWrapper **) VSICalloc(nBands,
225 0 : sizeof (WKTRasterBandWrapper *));
226 0 : if (papoBands == NULL) {
227 : CPLError(CE_Failure, CPLE_ObjectNull,
228 0 : "Couldn't allocate memory for raster wrapper bands, aborting");
229 0 : return FALSE;
230 : }
231 :
232 : // Create band objects
233 0 : for (int i = 0; i < nBands; i++) {
234 0 : GByte byFirstByteBandHeader = 0;
235 0 : int nPixTypeBytes = 0;
236 0 : double dfNoDataValue = 0.0;
237 :
238 : // TODO : check that there are enough bytes in the buffer
239 0 : memcpy(&byFirstByteBandHeader, pbyAuxPtr, sizeof (GByte));
240 0 : pbyAuxPtr += sizeof (GByte);
241 :
242 0 : switch (byFirstByteBandHeader & 0x0f) {
243 :
244 : /*
245 : * GByte is defined as "unsigned char" in cpl_port.h. The data
246 : * fetched from database (pointed by pbyAuxPtr) can be a "signed
247 : * char" (case 3) or "unsigned char" (cases 0, 1, 2, 4)
248 : */
249 : case 0: case 1: case 2: case 4:
250 : GByte byNoData;
251 0 : memcpy(&byNoData, pbyAuxPtr, sizeof(GByte));
252 0 : dfNoDataValue = (double)byNoData;
253 0 : nPixTypeBytes = sizeof(GByte);
254 0 : break;
255 : case 3:
256 : signed char sbyNoData;
257 0 : memcpy(&sbyNoData, pbyAuxPtr, sizeof(signed char));
258 0 : dfNoDataValue = (double)sbyNoData;
259 0 : nPixTypeBytes = sizeof(signed char);
260 0 : break;
261 : case 5:
262 : GInt16 n16NoData;
263 0 : memcpy(&n16NoData, pbyAuxPtr, sizeof(GInt16));
264 0 : dfNoDataValue = (double)n16NoData;
265 0 : nPixTypeBytes = sizeof(GInt16);
266 0 : break;
267 : case 6:
268 : GUInt16 un16NoData;
269 0 : memcpy(&un16NoData, pbyAuxPtr, sizeof(GUInt16));
270 0 : dfNoDataValue = (double)un16NoData;
271 0 : nPixTypeBytes = sizeof(GUInt16);
272 0 : break;
273 : case 7:
274 : GInt32 n32NoData;
275 0 : memcpy(&n32NoData, pbyAuxPtr, sizeof(GInt32));
276 0 : dfNoDataValue = (double)n32NoData;
277 0 : nPixTypeBytes = sizeof(GInt32);
278 0 : break;
279 : case 8:
280 : GUInt32 un32NoData;
281 0 : memcpy(&un32NoData, pbyAuxPtr, sizeof(GUInt32));
282 0 : dfNoDataValue = (double)un32NoData;
283 0 : nPixTypeBytes = sizeof(GUInt32);
284 0 : break;
285 : case 10:
286 : float fNoData;
287 0 : memcpy(&fNoData, pbyAuxPtr, sizeof(float));
288 0 : dfNoDataValue = (double)fNoData;
289 0 : nPixTypeBytes = sizeof(float);
290 0 : break;
291 : case 11:
292 0 : memcpy(&dfNoDataValue, pbyAuxPtr, sizeof(double));
293 0 : nPixTypeBytes = sizeof(double);
294 0 : break;
295 : default:
296 : // TODO: stop creating bands. Free memory for previous bands
297 :
298 : CPLError(CE_Failure, CPLE_NotSupported,
299 0 : "Nodata size not supported for band %d, aborting\n", i);
300 0 : return FALSE;
301 : }
302 :
303 : /***************************************************************
304 : * Swap nodata word, if needed
305 : ***************************************************************/
306 0 : if (byEndianess != byMachineEndianess)
307 0 : GDALSwapWords(&dfNoDataValue, nPixTypeBytes, 1, nPixTypeBytes);
308 0 : pbyAuxPtr += nPixTypeBytes;
309 :
310 0 : nRasterBandHeaderLen = (1 + nPixTypeBytes) * sizeof (GByte);
311 : nRasterDataLen = ((nLengthByWkbString - nRasterHeaderLen) / nBands) -
312 0 : ((1 + nPixTypeBytes));
313 :
314 : // TODO : check that there are enough bytes in the buffer
315 :
316 : /**************************************************************
317 : * In-db raster. Next bytes are the raster data and must be
318 : * swapped, if needed
319 : **************************************************************/
320 0 : if ((byFirstByteBandHeader >> 7) == FALSE) {
321 :
322 : // TODO: check this assertion, sometimes fails
323 : // In this case, data are a nWidth * nHeight array
324 : //CPLAssert(nRasterDataLen == (nWidth * nHeight * nPixTypeBytes));
325 :
326 : // Swap words of data, if needed
327 0 : if (byEndianess != byMachineEndianess)
328 : GDALSwapWords(pbyAuxPtr, nPixTypeBytes,
329 0 : nRasterDataLen / nPixTypeBytes, nPixTypeBytes);
330 :
331 : }
332 :
333 : // Create raster band wrapper object and set data
334 : // NOTE: All words has been swapped before creating band
335 0 : papoBands[i] = new WKTRasterBandWrapper(this, i + 1,
336 0 : byFirstByteBandHeader, dfNoDataValue);
337 0 : papoBands[i]->SetData(pbyAuxPtr, nRasterDataLen);
338 :
339 0 : pbyAuxPtr += nRasterDataLen;
340 :
341 : }
342 :
343 : // Set raster extent
344 0 : pszWktExtent = NULL;
345 :
346 0 : return TRUE;
347 : }
348 :
349 : /**
350 : * Class destructor. Frees the memory and resources allocated.
351 : */
352 0 : WKTRasterWrapper::~WKTRasterWrapper() {
353 0 : if (papoBands) {
354 0 : for (int i = 0; i < nBands; i++)
355 0 : delete papoBands[i];
356 0 : CPLFree(papoBands);
357 : }
358 :
359 0 : CPLFree(pszHexWkb);
360 0 : CPLFree(pbyHexWkb);
361 0 : CPLFree(pszWktExtent);
362 0 : }
363 :
364 : /**
365 : * Creates a polygon in WKT representation that wrapps all the extent
366 : * covered by the raster
367 : * Parameters: nothing
368 : * Returns:
369 : * char *: The polygon in WKT format
370 : */
371 0 : const char * WKTRasterWrapper::GetWktExtent() {
372 : /**
373 : * Create WKT string for raster extent
374 : * TODO: With irregular blocking is not valid in this way...
375 : */
376 0 : double dfRasterWidth = ABS((int) (dfScaleX * nWidth + 0.5));
377 0 : double dfRasterHeight = ABS((int) (dfScaleY * nHeight + 0.5));
378 :
379 0 : double dfBlockEndX = dfIpX + dfRasterWidth;
380 0 : double dfBlockEndY = dfIpY - dfRasterHeight;
381 : char szTemp[1024];
382 :
383 : sprintf(szTemp,
384 : "POLYGON((%f %f, %f %f ,%f %f ,%f %f, %f %f))", dfIpX, dfBlockEndY,
385 : dfIpX, dfIpY, dfBlockEndX, dfBlockEndY, dfBlockEndX, dfIpY, dfIpX,
386 0 : dfBlockEndY);
387 :
388 0 : CPLFree(pszWktExtent);
389 0 : pszWktExtent = CPLStrdup(szTemp);
390 :
391 0 : return pszWktExtent;
392 : }
393 :
394 : /**
395 : * Constructs the binary representation of the PostGIS WKT raster wrapped
396 : * by this class, based on all the class properties.
397 : * This method swaps words if the raster endianess is distinct from
398 : * the machine endianess.
399 : * Parameters: nothing
400 : * Returns:
401 : * - GByte *: Binary representation of the hexwkb string
402 : */
403 0 : GByte * WKTRasterWrapper::GetBinaryRepresentation() {
404 :
405 0 : GByte byMachineEndianess = NDR; // by default
406 :
407 : // Check machine endianess
408 : #ifdef CPL_LSB
409 0 : byMachineEndianess = NDR;
410 : #else
411 : byMachineEndianess = XDR;
412 : #endif
413 :
414 0 : int nTransformedBytes = 0;
415 0 : int nPixTypeBytes = 0;
416 :
417 : GByte * pbyTmpRepresentation = (GByte *) VSICalloc(nLengthByWkbString,
418 0 : sizeof (GByte));
419 0 : if (pbyTmpRepresentation == NULL) {
420 : CPLError(CE_Warning, CPLE_ObjectNull,
421 : "Couldn't allocate memory for generating the binary \
422 0 : representation of the raster. Using the original one");
423 :
424 0 : return pbyHexWkb;
425 : }
426 :
427 : // We'll use this pointer for moving over the representation
428 0 : GByte * pbyAuxPtr = pbyTmpRepresentation;
429 :
430 : // Copy the attributes in the array
431 0 : memcpy(pbyAuxPtr, &byEndianess, sizeof (GByte));
432 0 : nTransformedBytes += sizeof (GByte);
433 0 : pbyAuxPtr += sizeof (GByte);
434 :
435 0 : memcpy(pbyAuxPtr, &nVersion, sizeof (GUInt16));
436 0 : if (byEndianess != byMachineEndianess)
437 0 : GDALSwapWords(pbyAuxPtr, sizeof (GUInt16), 1, sizeof (GUInt16));
438 0 : nTransformedBytes += sizeof (GUInt16);
439 0 : pbyAuxPtr += sizeof (GUInt16);
440 :
441 0 : memcpy(pbyAuxPtr, &nBands, sizeof (GUInt16));
442 0 : if (byEndianess != byMachineEndianess)
443 0 : GDALSwapWords(pbyAuxPtr, sizeof (GUInt16), 1, sizeof (GUInt16));
444 0 : nTransformedBytes += sizeof (GUInt16);
445 0 : pbyAuxPtr += sizeof (GUInt16);
446 :
447 0 : memcpy(pbyAuxPtr, &dfScaleX, sizeof (double));
448 0 : if (byEndianess != byMachineEndianess)
449 0 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1, sizeof (double));
450 0 : nTransformedBytes += sizeof (double);
451 0 : pbyAuxPtr += sizeof (double);
452 :
453 0 : memcpy(pbyAuxPtr, &dfScaleY, sizeof (double));
454 0 : if (byEndianess != byMachineEndianess)
455 0 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1, sizeof (double));
456 0 : nTransformedBytes += sizeof (double);
457 0 : pbyAuxPtr += sizeof (double);
458 :
459 0 : memcpy(pbyAuxPtr, &dfIpX, sizeof (double));
460 0 : if (byEndianess != byMachineEndianess)
461 0 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1, sizeof (double));
462 0 : nTransformedBytes += sizeof (double);
463 0 : pbyAuxPtr += sizeof (double);
464 :
465 0 : memcpy(pbyAuxPtr, &dfIpY, sizeof (double));
466 0 : if (byEndianess != byMachineEndianess)
467 0 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1, sizeof (double));
468 0 : nTransformedBytes += sizeof (double);
469 0 : pbyAuxPtr += sizeof (double);
470 :
471 0 : memcpy(pbyAuxPtr, &dfSkewX, sizeof (double));
472 0 : if (byEndianess != byMachineEndianess)
473 0 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1, sizeof (double));
474 0 : nTransformedBytes += sizeof (double);
475 0 : pbyAuxPtr += sizeof (double);
476 :
477 0 : memcpy(pbyAuxPtr, &dfSkewY, sizeof (double));
478 0 : if (byEndianess != byMachineEndianess)
479 0 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1, sizeof (double));
480 0 : nTransformedBytes += sizeof (double);
481 0 : pbyAuxPtr += sizeof (double);
482 :
483 0 : memcpy(pbyAuxPtr, &nSrid, sizeof (GInt32));
484 0 : if (byEndianess != byMachineEndianess)
485 0 : GDALSwapWords(pbyAuxPtr, sizeof (GInt32), 1, sizeof (GInt32));
486 0 : nTransformedBytes += sizeof (GInt32);
487 0 : pbyAuxPtr += sizeof (GInt32);
488 :
489 0 : memcpy(pbyAuxPtr, &nWidth, sizeof (GUInt16));
490 0 : if (byEndianess != byMachineEndianess)
491 0 : GDALSwapWords(pbyAuxPtr, sizeof (GUInt16), 1, sizeof (GUInt16));
492 0 : nTransformedBytes += sizeof (GUInt16);
493 0 : pbyAuxPtr += sizeof (GUInt16);
494 :
495 0 : memcpy(pbyAuxPtr, &nHeight, sizeof (GUInt16));
496 0 : if (byEndianess != byMachineEndianess)
497 0 : GDALSwapWords(pbyAuxPtr, sizeof (GUInt16), 1, sizeof (GUInt16));
498 0 : nTransformedBytes += sizeof (GUInt16);
499 0 : pbyAuxPtr += sizeof (GUInt16);
500 :
501 0 : for (int i = 0; i < nBands; i++) {
502 : /**
503 : * We're going to create one byte using some bits of three fields:
504 : * - bIsOffline: _ _ _ _ _ _ _ X
505 : * - byReserved: _ _ _ _ _ X X X
506 : * - byPixelType: _ _ _ _ X X X X
507 : * So, we'll have to move each byte a number of bits to put the 'X'
508 : * into consecutive positions in the final result byte
509 : */
510 : GByte byFirstByteOfBandHeader =
511 0 : (papoBands[i]->bIsOffline << 7) +
512 0 : (papoBands[i]->byReserved << 4) +
513 0 : (papoBands[i]->byPixelType & 0x0f);
514 0 : memcpy(pbyAuxPtr, &byFirstByteOfBandHeader, sizeof (GByte));
515 0 : nTransformedBytes += sizeof (GByte);
516 0 : pbyAuxPtr += sizeof (GByte);
517 :
518 : /**
519 : * Copy nodata value. Its size depends on the pixel type
520 : * NOTE: But this size CAN'T BE CHANGED, it will be the same of the
521 : * original nodata size's value. If not, we couldn't know how much
522 : * memory need.
523 : */
524 :
525 : // FIXME : this is likely incorrect. see previous FIXME
526 0 : switch (papoBands[i]->byPixelType & 0x0f) {
527 : case 0: case 1: case 2: case 4:
528 0 : nPixTypeBytes = 1;
529 0 : memcpy(pbyAuxPtr, (GByte *) (&papoBands[i]->dfNodata),
530 0 : sizeof (GByte));
531 0 : if (byEndianess != byMachineEndianess)
532 : GDALSwapWords(pbyAuxPtr, sizeof (GByte), 1,
533 0 : sizeof (GByte));
534 0 : pbyAuxPtr += sizeof (GByte);
535 0 : nTransformedBytes += sizeof (GByte);
536 0 : break;
537 : case 3:
538 0 : nPixTypeBytes = 1;
539 0 : memcpy(pbyAuxPtr, (signed char *) (&papoBands[i]->dfNodata),
540 0 : sizeof (signed char));
541 0 : if (byEndianess != byMachineEndianess)
542 : GDALSwapWords(pbyAuxPtr, sizeof (signed char), 1,
543 0 : sizeof (signed char));
544 0 : pbyAuxPtr += sizeof (signed char);
545 0 : nTransformedBytes += sizeof (signed char);
546 0 : break;
547 : case 5:
548 0 : nPixTypeBytes = 2;
549 0 : memcpy(pbyAuxPtr, (GInt16 *) (&papoBands[i]->dfNodata),
550 0 : sizeof (GInt16));
551 0 : if (byEndianess != byMachineEndianess)
552 : GDALSwapWords(pbyAuxPtr, sizeof (GInt16), 1,
553 0 : sizeof (GInt16));
554 0 : nTransformedBytes += sizeof (GInt16);
555 0 : pbyAuxPtr += sizeof (GInt16);
556 0 : break;
557 : case 6:
558 0 : nPixTypeBytes = 2;
559 0 : memcpy(pbyAuxPtr, (GUInt16 *) (&papoBands[i]->dfNodata),
560 0 : sizeof (GUInt16));
561 0 : if (byEndianess != byMachineEndianess)
562 : GDALSwapWords(pbyAuxPtr, sizeof (GUInt16), 1,
563 0 : sizeof (GUInt16));
564 0 : nTransformedBytes += sizeof (GUInt16);
565 0 : pbyAuxPtr += sizeof (GUInt16);
566 0 : break;
567 : case 7:
568 0 : nPixTypeBytes = 4;
569 0 : memcpy(pbyAuxPtr, (GInt32 *) (&papoBands[i]->dfNodata),
570 0 : sizeof (GInt32));
571 0 : if (byEndianess != byMachineEndianess)
572 : GDALSwapWords(pbyAuxPtr, sizeof (GInt32), 1,
573 0 : sizeof (GInt32));
574 0 : nTransformedBytes += sizeof (GInt32);
575 0 : pbyAuxPtr += sizeof (GInt32);
576 0 : break;
577 : case 8:
578 0 : nPixTypeBytes = 4;
579 0 : memcpy(pbyAuxPtr, (GUInt32 *) (&papoBands[i]->dfNodata),
580 0 : sizeof (GUInt32));
581 0 : if (byEndianess != byMachineEndianess)
582 : GDALSwapWords(pbyAuxPtr, sizeof (GUInt32), 1,
583 0 : sizeof (GUInt32));
584 0 : nTransformedBytes += sizeof (GUInt32);
585 0 : pbyAuxPtr += sizeof (GUInt32);
586 0 : break;
587 : case 10:
588 0 : nPixTypeBytes = 8;
589 0 : memcpy(pbyAuxPtr, &(papoBands[i]->dfNodata), sizeof (float));
590 0 : if (byEndianess != byMachineEndianess)
591 : GDALSwapWords(pbyAuxPtr, sizeof (float), 1,
592 0 : sizeof (float));
593 0 : pbyAuxPtr += sizeof (float);
594 0 : nTransformedBytes += sizeof (float);
595 0 : break;
596 : case 11:
597 0 : nPixTypeBytes = 8;
598 0 : memcpy(pbyAuxPtr, &(papoBands[i]->dfNodata), sizeof (double));
599 0 : if (byEndianess != byMachineEndianess)
600 : GDALSwapWords(pbyAuxPtr, sizeof (double), 1,
601 0 : sizeof (double));
602 0 : pbyAuxPtr += sizeof (double);
603 0 : nTransformedBytes += sizeof (double);
604 0 : break;
605 : default:
606 : CPLError(CE_Failure, CPLE_NotSupported,
607 : "Nodata size not supported for band %d, using the original \
608 0 : one\n",i);
609 0 : return pbyHexWkb;
610 : }
611 :
612 :
613 : // out-db band
614 0 : if (papoBands[i]->bIsOffline == TRUE) {
615 :
616 : // copy outdb band number
617 0 : memcpy(pbyAuxPtr, &(papoBands[i]->nOutDbBandNumber), sizeof (GByte));
618 0 : pbyAuxPtr += sizeof (GByte);
619 0 : nTransformedBytes += sizeof (GByte);
620 :
621 : // copy path to the external file (pbyData). Don't need to swap
622 0 : memcpy(pbyAuxPtr, papoBands[i]->pbyData, papoBands[i]->nDataSize);
623 0 : pbyAuxPtr += papoBands[i]->nDataSize * sizeof (GByte);
624 0 : nTransformedBytes += papoBands[i]->nDataSize * sizeof (GByte);
625 :
626 : }
627 : // in-db band
628 : else {
629 : // Copy data
630 0 : memcpy(pbyAuxPtr, papoBands[i]->pbyData, papoBands[i]->nDataSize);
631 0 : if (byEndianess != byMachineEndianess)
632 : GDALSwapWords(pbyAuxPtr, nPixTypeBytes,
633 0 : papoBands[i]->nDataSize / nPixTypeBytes, nPixTypeBytes);
634 0 : pbyAuxPtr += papoBands[i]->nDataSize * sizeof (GByte);
635 0 : nTransformedBytes += papoBands[i]->nDataSize * sizeof (GByte);
636 : }
637 :
638 : }
639 :
640 : /**
641 : * Now, copy the new binary array into the old one and free the allocated
642 : * memory
643 : */
644 : // TODO: Check this assert. Sometimes fails
645 : //CPLAssert(nTransformedBytes == nLengthByWkbString);
646 : memcpy(pbyHexWkb, pbyTmpRepresentation, nTransformedBytes *
647 0 : sizeof (GByte));
648 0 : CPLFree(pbyTmpRepresentation);
649 :
650 0 : return pbyHexWkb;
651 : }
652 :
653 : /**
654 : * Constructs the hexwkb representation of the PostGIS WKT raster wrapped
655 : * by this class, based on all the class properties.
656 : * This method swaps words if the raster endianess is distinct from
657 : * the machine endianess.
658 : * Parameters: nothing
659 : * Returns:
660 : * - GByte *: Hexwkb string
661 : */
662 0 : char * WKTRasterWrapper::GetHexWkbRepresentation() {
663 0 : GetBinaryRepresentation();
664 : char * pszAuxRepresentation = CPLBinaryToHex(nLengthByWkbString,
665 0 : pbyHexWkb);
666 :
667 0 : if (pszAuxRepresentation == NULL) {
668 : CPLError(CE_Warning, CPLE_ObjectNull,
669 : "Couldn't allocate memory for generating the HexWkb \
670 0 : representation of the raster. Using the original one");
671 :
672 0 : return pszHexWkb;
673 : }
674 :
675 : CPLAssert((int)strlen(pszAuxRepresentation) == nLengthHexWkbString);
676 : memcpy(pszHexWkb, pszAuxRepresentation, nLengthByWkbString *
677 0 : sizeof (char));
678 :
679 0 : CPLFree(pszAuxRepresentation);
680 :
681 0 : return pszHexWkb;
682 : }
683 :
684 : /**
685 : * Gets a wrapper of a RasterBand, as a WKTRasterBandWrapper object.
686 : * Properties:
687 : * - GUInt16: the band number.
688 : * Returns:
689 : * - WKTRasterWrapper *: an object that wrapps the RasterBand
690 : */
691 0 : WKTRasterBandWrapper * WKTRasterWrapper::GetBand(GUInt16 nBandNumber) {
692 0 : if (nBandNumber == 0 || nBandNumber > nBands) {
693 : CPLError(CE_Failure, CPLE_IllegalArg,
694 0 : "Couldn't get band number %d", nBandNumber);
695 0 : return NULL;
696 : }
697 :
698 0 : return papoBands[nBandNumber - 1];
699 : }
700 :
701 : /**************************************************************************
702 : * ======================================================================
703 : * WKTRasterBandWrapper
704 : * ======================================================================
705 : *
706 : * This class wrapps the HEXWKB representation of a PostGIS WKT Raster
707 : * Band, that is a part of the wrapper of a WKT Raster.
708 : *
709 : * TODO:
710 : * - Allow changing the size of the nodatavalue, that implies modify the
711 : * allocated memory for HexWkb representation of the WKT Raster. Now, you
712 : * only can change the value, not the size.
713 : * - Avoid the use of double instead of double, to ensure compatibility
714 : * with WKTRasterRasterBand types. Discuss it.
715 : ***************************************************************************/
716 :
717 : /**
718 : * Constructor.
719 : * Parameters:
720 : * - WKTRasterWrapper *: the WKT Raster wrapper this band belongs to
721 : * - GUInt16: band number
722 : * - GByte: The first byte of the band header (contains the value for
723 : * other class properties).
724 : * - double: The nodata value. Could be any kind of data (GByte,
725 : * GUInt16, GInt32...) but the variable has the bigger type
726 : */
727 0 : WKTRasterBandWrapper::WKTRasterBandWrapper(WKTRasterWrapper * poWKTRW,
728 : GUInt16 nBandNumber, GByte byFirstByteOfHeader, double fNodataValue) {
729 :
730 0 : bIsOffline = byFirstByteOfHeader >> 7;
731 0 : byReserved = (byFirstByteOfHeader >> 4) & 0x07;
732 0 : byPixelType = byFirstByteOfHeader & 0x0f;
733 0 : dfNodata = fNodataValue;
734 0 : nBand = nBandNumber;
735 0 : poRW = poWKTRW;
736 0 : pbyData = NULL;
737 0 : nOutDbBandNumber = -1;
738 0 : }
739 :
740 : /**
741 : * Class destructor. Frees the memory and resources allocated.
742 : */
743 0 : WKTRasterBandWrapper::~WKTRasterBandWrapper() {
744 0 : CPLFree(pbyData);
745 0 : }
746 :
747 : /**
748 : * Set the raster band data. This method updates the data of the raster
749 : * band. Then, when the HexWkb representation of the raster is
750 : * required (via WKTRasterWrapper::GetBinaryRepresentation or
751 : * WKTRasterWrapper::GetHexWkbRepresentation), the new data will
752 : * be packed instead the data of the original HexWkb representation
753 : * used to create the WKTRasterWrapper.
754 : * Parameters:
755 : * - GByte *: The data to set
756 : * - GUInt32: data size
757 : * Returns:
758 : * - CE_None if the data is set, CE_Failure otherwise
759 : */
760 0 : CPLErr WKTRasterBandWrapper::SetData(GByte * pbyDataArray, GUInt32 nSize) {
761 :
762 : /**************************************************************
763 : * If we have an out-db raster, the next bytes will represent:
764 : * - bandNumber: 0-based band number to use from ext. file
765 : * - path to the external file
766 : * In this case, we must extract the band number from the data
767 : **************************************************************/
768 : GByte * pbyAux;
769 0 : int nSizeMemToAllocate = 0;
770 :
771 : // Security checking
772 0 : if (pbyDataArray == NULL) {
773 : CPLError(CE_Warning, CPLE_ObjectNull,
774 0 : "Couldn't set data for raster band %d", nBand);
775 0 : nDataSize = 0;
776 0 : return CE_Failure;
777 : }
778 : /**********************************************************
779 : * Out-db raster: extract the band number first, and
780 : * copy the rest of the data (will be the path to file)
781 : **********************************************************/
782 0 : else if (bIsOffline == TRUE) {
783 0 : memcpy(&nOutDbBandNumber, pbyDataArray, sizeof (GByte));
784 0 : nSizeMemToAllocate = nSize - sizeof (GByte);
785 0 : pbyAux = pbyDataArray + sizeof (GByte);
786 :
787 : // the bandnumber read is 0-based
788 0 : nOutDbBandNumber++;
789 : }
790 :
791 : /*********************************************************
792 : * In-db raster: all the buffer is the data.
793 : *********************************************************/
794 : else {
795 0 : nOutDbBandNumber = -1;
796 0 : nSizeMemToAllocate = nSize;
797 0 : pbyAux = pbyDataArray;
798 : }
799 :
800 :
801 : /*********************************************************
802 : * Now, really copy the data buffer to the class property
803 : *********************************************************/
804 0 : CPLFree(pbyData);
805 0 : pbyData = (GByte *) VSICalloc(nSizeMemToAllocate, sizeof (GByte));
806 0 : if (pbyData == NULL) {
807 : CPLError(CE_Failure, CPLE_ObjectNull,
808 : "Couldn't allocate memory for raster data in band %d",
809 0 : nBand);
810 0 : nDataSize = 0;
811 0 : return CE_Failure;
812 : } else {
813 0 : memcpy(pbyData, pbyAux, nSizeMemToAllocate);
814 0 : nDataSize = nSizeMemToAllocate;
815 0 : return CE_None;
816 : }
817 :
818 : }
819 :
820 : /**
821 : * Get the raster band data.
822 : * Parameters: nothing
823 : * Returns:
824 : * - GByte *: The raster band data
825 : */
826 0 : GByte * WKTRasterBandWrapper::GetData() {
827 : /**
828 : * NOTE: The data could be a path to a file. In this case, the string
829 : * representing the path may contain zeros at the end. But I need that
830 : * is not necessary to "cut" these zeros (the functions that uses the
831 : * name of a file should read until the first zero of the string...
832 : */
833 0 : return pbyData;
834 : }
|