LCOV - code coverage report
Current view: directory - frmts/wktraster - wktrasterwrapper.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 360 0 0.0 %
Date: 2010-01-09 Functions: 11 0 0.0 %

       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                 : }

Generated by: LCOV version 1.7