1 /******************************************************************************
2  *
3  * File :    pgchipdataset.cpp
4  * Project:  PGCHIP Driver
5  * Purpose:  GDALDataset code for POSTGIS CHIP/GDAL Driver
6  * Author:   Benjamin Simon, noumayoss@gmail.com
7  *
8  ******************************************************************************
9  * Copyright (c) 2005, Benjamin Simon, noumayoss@gmail.com
10  * Copyright (c) 2008, Even Rouault <even dot rouault at mines-paris dot 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  *
31  * Revision 1.1  2005/08/29 bsimon
32  * New
33  *
34  */
35 
36 #include "pgchip.h"
37 
38 /* Define to enable debugging info */
39 /*#define PGCHIP_DEBUG 1*/
40 
41 CPL_C_START
42 void	GDALRegister_PGCHIP(void);
43 CPL_C_END
44 
45 
46 /************************************************************************/
47 /* ==================================================================== */
48 /*				PGCHIPDataset				*/
49 /* ==================================================================== */
50 /************************************************************************/
51 
52 
53 /************************************************************************/
54 /*                            PGCHIPDataset()                           */
55 /************************************************************************/
56 
PGCHIPDataset()57 PGCHIPDataset::PGCHIPDataset(){
58 
59     hPGConn = NULL;
60     pszTableName = NULL;
61     pszDSName = NULL;
62     PGCHIP = NULL;
63 
64     bGeoTransformValid = FALSE;
65     adfGeoTransform[0] = 0.0;
66     adfGeoTransform[1] = 1.0;
67     adfGeoTransform[2] = 0.0;
68     adfGeoTransform[3] = 0.0;
69     adfGeoTransform[4] = 0.0;
70     adfGeoTransform[5] = 1.0;
71 
72     SRID = -1;
73     pszProjection = CPLStrdup("");
74 
75     bHaveNoData = FALSE;
76     dfNoDataValue = -1;
77 }
78 
79 /************************************************************************/
80 /*                            ~PGCHIPDataset()                             */
81 /************************************************************************/
82 
~PGCHIPDataset()83 PGCHIPDataset::~PGCHIPDataset(){
84 
85     if( hPGConn != NULL )
86     {
87         /* XXX - mloskot: After the connection is closed, valgrind still
88          * reports 36 bytes definitely lost, somewhere in the libpq.
89          */
90         PQfinish( hPGConn );
91         hPGConn = NULL;
92     }
93 
94     CPLFree(pszProjection);
95     CPLFree(pszTableName);
96     CPLFree(pszDSName);
97     CPLFree(PGCHIP);
98 }
99 
100 /************************************************************************/
101 /*                          GetGeoTransform()                           */
102 /************************************************************************/
103 
GetGeoTransform(double * padfTransform)104 CPLErr PGCHIPDataset::GetGeoTransform( double * padfTransform ){
105 
106     memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
107 
108     if( bGeoTransformValid )
109         return CE_None;
110     else
111         return CE_Failure;
112 }
113 
114 /************************************************************************/
115 /*                          GetProjectionRef()                          */
116 /************************************************************************/
117 
GetProjectionRef()118 const char *PGCHIPDataset::GetProjectionRef(){
119 
120     char    szCommand[1024];
121     PGresult    *hResult;
122 
123     if(SRID == -1)
124     {
125         return "";
126     }
127 
128 /* -------------------------------------------------------------------- */
129 /*      Reading proj                                                    */
130 /* -------------------------------------------------------------------- */
131 
132     sprintf( szCommand,"SELECT srtext FROM spatial_ref_sys where SRID=%d",SRID);
133 
134     hResult = PQexec(hPGConn,szCommand);
135 
136     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
137              && PQntuples(hResult) > 0 )
138     {
139         CPLFree(pszProjection);
140         pszProjection = CPLStrdup(PQgetvalue(hResult,0,0));
141     }
142 
143     if( hResult )
144         PQclear( hResult );
145 
146     return pszProjection;
147 }
148 
149 /************************************************************************/
150 /*                        PGChipOpenConnection()                        */
151 /************************************************************************/
152 
153 static
PGChipOpenConnection(const char * pszFilename,char ** ppszTableName,const char ** ppszDSName,int bExitOnMissingTable,int * pbExistTable,int * pbHasNameCol)154 PGconn* PGChipOpenConnection(const char* pszFilename, char** ppszTableName, const char** ppszDSName,
155                              int bExitOnMissingTable, int* pbExistTable, int *pbHasNameCol)
156 {
157     char       *pszConnectionString;
158     PGconn     *hPGConn;
159     PGresult   *hResult = NULL;
160     int         i=0;
161     int         bHavePostGIS;
162     char       *pszTableName;
163     char        szCommand[1024];
164 
165     if( pszFilename == NULL || !EQUALN(pszFilename,"PG:",3))
166         return NULL;
167 
168     pszConnectionString = CPLStrdup(pszFilename);
169 
170 /* -------------------------------------------------------------------- */
171 /*      Try to establish connection.                                    */
172 /* -------------------------------------------------------------------- */
173     while(pszConnectionString[i] != '\0')
174     {
175 
176         if(pszConnectionString[i] == '#')
177             pszConnectionString[i] = ' ';
178         else if(pszConnectionString[i] == '%')
179         {
180             pszConnectionString[i] = '\0';
181             break;
182         }
183         i++;
184     }
185 
186     hPGConn = PQconnectdb( pszConnectionString + 3 );
187     if( hPGConn == NULL || PQstatus(hPGConn) == CONNECTION_BAD )
188     {
189         CPLError( CE_Failure, CPLE_AppDefined,
190                   "PGconnectcb failed.\n%s",
191                   PQerrorMessage(hPGConn) );
192         PQfinish(hPGConn);
193         CPLFree(pszConnectionString);
194         return NULL;
195     }
196 
197 /* -------------------------------------------------------------------- */
198 /*      Test to see if this database instance has support for the       */
199 /*      PostGIS Geometry type.  If so, disable sequential scanning      */
200 /*      so we will get the value of the gist indexes.                   */
201 /* -------------------------------------------------------------------- */
202 
203     hResult = PQexec(hPGConn,
204                          "SELECT oid FROM pg_type WHERE typname = 'geometry'" );
205 
206     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
207         && PQntuples(hResult) > 0 )
208     {
209         bHavePostGIS = TRUE;
210     }
211 
212     if( hResult )
213         PQclear( hResult );
214 
215     if(!bHavePostGIS){
216         CPLError( CE_Failure, CPLE_AppDefined,
217                       "Can't find geometry type, is Postgis correctly installed ?\n");
218         PQfinish(hPGConn);
219         CPLFree(pszConnectionString);
220         return NULL;
221     }
222 
223 /* -------------------------------------------------------------------- */
224 /*  Try opening the layer                                               */
225 /* -------------------------------------------------------------------- */
226 
227     if( strstr(pszFilename, "layer=") != NULL )
228     {
229         pszTableName = CPLStrdup( strstr(pszFilename, "layer=") + 6 );
230     }
231     else
232     {
233         pszTableName = CPLStrdup("unknown_layer");
234     }
235 
236     char* pszDSName = strstr(pszTableName, "%name=");
237     if (pszDSName)
238     {
239         *pszDSName = '\0';
240         pszDSName += 6;
241     }
242     else
243         pszDSName = "unknown_name";
244 
245     sprintf( szCommand,
246              "select b.attname from pg_class a,pg_attribute b where a.oid=b.attrelid and a.relname='%s' and b.attname='raster';",
247               pszTableName);
248 
249     hResult = PQexec(hPGConn,szCommand);
250 
251     if( ! (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK && PQntuples(hResult) > 0) )
252     {
253         if (pbExistTable)
254             *pbExistTable = FALSE;
255 
256         if (bExitOnMissingTable)
257         {
258             if (hResult)
259                 PQclear( hResult );
260             CPLFree(pszConnectionString);
261             CPLFree(pszTableName);
262             PQfinish(hPGConn);
263             return NULL;
264         }
265     }
266     else
267     {
268         if (pbExistTable)
269             *pbExistTable = TRUE;
270 
271         sprintf( szCommand,
272                 "select b.attname from pg_class a,pg_attribute b where a.oid=b.attrelid and a.relname='%s' and b.attname='name';",
273                 pszTableName);
274 
275         if (hResult)
276             PQclear( hResult );
277         hResult = PQexec(hPGConn,szCommand);
278         if (PQresultStatus(hResult) == PGRES_TUPLES_OK && PQntuples(hResult) > 0)
279         {
280             if (pbHasNameCol)
281                 *pbHasNameCol = TRUE;
282         }
283         else
284         {
285             if (pbHasNameCol)
286                 *pbHasNameCol = FALSE;
287         }
288     }
289 
290     if (hResult)
291         PQclear( hResult );
292 
293     if (ppszTableName)
294         *ppszTableName = pszTableName;
295     else
296         CPLFree(pszTableName);
297 
298     if (ppszDSName)
299         *ppszDSName = pszDSName;
300 
301     CPLFree(pszConnectionString);
302 
303     return hPGConn;
304 }
305 
306 
307 
308 /************************************************************************/
309 /*                                Open()                                */
310 /************************************************************************/
311 
Open(GDALOpenInfo * poOpenInfo)312 GDALDataset *PGCHIPDataset::Open( GDALOpenInfo * poOpenInfo ){
313 
314     char                szCommand[1024];
315     PGresult            *hResult = NULL;
316     PGCHIPDataset       *poDS = NULL;
317     char                *chipStringHex;
318 
319     unsigned char       *chipdata;
320     int                 t;
321     char                *pszTableName = NULL;
322     const char          *pszDSName = NULL;
323     int                  bHasNameCol = FALSE;
324 
325     PGconn* hPGConn = PGChipOpenConnection(poOpenInfo->pszFilename, &pszTableName, &pszDSName, TRUE, NULL, &bHasNameCol);
326 
327     if( hPGConn == NULL)
328         return NULL;
329 
330     poDS = new PGCHIPDataset();
331     poDS->hPGConn = hPGConn;
332     poDS->pszTableName = pszTableName;
333     poDS->pszDSName = CPLStrdup(pszDSName);
334 
335 /* -------------------------------------------------------------------- */
336 /*      Read the chip                                                   */
337 /* -------------------------------------------------------------------- */
338 
339     hResult = PQexec(poDS->hPGConn, "BEGIN");
340 
341     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
342     {
343         PQclear( hResult );
344         if (bHasNameCol)
345             sprintf( szCommand,
346                     "SELECT raster FROM %s WHERE name = '%s' LIMIT 1 ",
347                     poDS->pszTableName, poDS->pszDSName);
348         else
349             sprintf( szCommand,
350                     "SELECT raster FROM %s LIMIT 1",
351                     poDS->pszTableName);
352 
353         hResult = PQexec(poDS->hPGConn,szCommand);
354     }
355 
356     if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
357     {
358         CPLError( CE_Failure, CPLE_AppDefined,
359                   "%s", PQerrorMessage(poDS->hPGConn) );
360         if (hResult)
361             PQclear( hResult );
362         delete poDS;
363         return NULL;
364     }
365 
366     if (PQntuples(hResult) == 0)
367     {
368         PQclear( hResult );
369         delete poDS;
370         return NULL;
371     }
372 
373     chipStringHex = PQgetvalue(hResult, 0, 0);
374 
375     if (chipStringHex == NULL)
376     {
377         PQclear( hResult );
378         delete poDS;
379         return NULL;
380     }
381 
382     int stringlen = strlen((char *)chipStringHex);
383 
384     // Allocating memory for chip
385     chipdata = (unsigned char *) CPLMalloc(stringlen/2);
386 
387     for (t=0;t<stringlen/2;t++){
388 	    chipdata[t] = parse_hex( &chipStringHex[t*2]) ;
389     }
390 
391     // Chip assigment
392     poDS->PGCHIP = (CHIP *)chipdata;
393     poDS->SRID = poDS->PGCHIP->SRID;
394 
395     if (poDS->PGCHIP->bvol.xmin != 0 && poDS->PGCHIP->bvol.ymin != 0 &
396         poDS->PGCHIP->bvol.xmax != 0 && poDS->PGCHIP->bvol.ymax != 0)
397     {
398         poDS->bGeoTransformValid = TRUE;
399 
400         poDS->adfGeoTransform[0] = poDS->PGCHIP->bvol.xmin;
401         poDS->adfGeoTransform[3] = poDS->PGCHIP->bvol.ymax;
402         poDS->adfGeoTransform[1] = (poDS->PGCHIP->bvol.xmax - poDS->PGCHIP->bvol.xmin) / poDS->PGCHIP->width;
403         poDS->adfGeoTransform[5] = - (poDS->PGCHIP->bvol.ymax - poDS->PGCHIP->bvol.ymin) / poDS->PGCHIP->height;
404     }
405 
406 #ifdef PGCHIP_DEBUG
407     poDS->printChipInfo(*(poDS->PGCHIP));
408 #endif
409 
410     PQclear( hResult );
411 
412     hResult = PQexec(poDS->hPGConn, "COMMIT");
413     PQclear( hResult );
414 
415 /* -------------------------------------------------------------------- */
416 /*      Verify that there's no unknown field set.                       */
417 /* -------------------------------------------------------------------- */
418 
419     if ( poDS->PGCHIP->future[0] != 0 ||
420          poDS->PGCHIP->future[1] != 0 ||
421          poDS->PGCHIP->future[2] != 0 ||
422          poDS->PGCHIP->future[3] != 0 )
423     {
424         CPLError( CE_Failure, CPLE_AppDefined,
425                   "Unsupported CHIP format (future field bytes != 0)\n");
426         delete poDS;
427         return NULL;
428     }
429 
430     if ( poDS->PGCHIP->compression != 0 )
431     {
432         CPLError( CE_Failure, CPLE_AppDefined,
433                   "Compressed CHIP unsupported\n");
434         delete poDS;
435         return NULL;
436     }
437 
438 /* -------------------------------------------------------------------- */
439 /*      Set some information from the file that is of interest.         */
440 /* -------------------------------------------------------------------- */
441 
442     poDS->nRasterXSize = poDS->PGCHIP->width;
443     poDS->nRasterYSize = poDS->PGCHIP->height;
444     poDS->nBands = 1; // (int)poDS->PGCHIP->future[0];
445     //poDS->nBitDepth = (int)poDS->PGCHIP->future[1];
446     poDS->nColorType = PGCHIP_COLOR_TYPE_GRAY; //(int)poDS->PGCHIP->future[2];
447 
448     switch (poDS->PGCHIP->datatype)
449     {
450         case 5: // 24bit integer
451             poDS->nBitDepth = 24;
452             break;
453         case 6: // 16bit integer
454             poDS->nBitDepth = 16;
455             break;
456         case 8:
457             poDS->nBitDepth = 8;
458             break;
459         case 1: // float32
460         case 7: // 16bit ???
461         case 101: // float32 (NDR)
462         case 105: // 24bit integer (NDR)
463         case 106: // 16bit integer (NDR)
464         case 107: // 16bit ??? (NDR)
465         case 108: // 8bit ??? (NDR) [ doesn't make sense ]
466         default :
467              CPLError( CE_Failure, CPLE_AppDefined,
468                 "Under development : CHIP datatype %d unsupported.\n",
469                 poDS->PGCHIP->datatype);
470             break;
471     }
472 
473 
474 /* -------------------------------------------------------------------- */
475 /*      Create band information objects.                                */
476 /* -------------------------------------------------------------------- */
477     for( int iBand = 0; iBand < poDS->nBands; iBand++ )
478         poDS->SetBand( iBand+1, new PGCHIPRasterBand( poDS, iBand+1 ) );
479 
480 
481 /* -------------------------------------------------------------------- */
482 /*      Is there a palette?  Note: we should also read back and         */
483 /*      apply transparency values if available.                         */
484 /* -------------------------------------------------------------------- */
485     CPLAssert (poDS->nColorType != PGCHIP_COLOR_TYPE_PALETTE);
486     if( poDS->nColorType == PGCHIP_COLOR_TYPE_PALETTE )
487     {
488         unsigned char *pPalette;
489         int	nColorCount = 0;
490         int     sizePalette = 0;
491         int     offsetColor = -1;
492         GDALColorEntry oEntry;
493 
494         nColorCount = (int)poDS->PGCHIP->compression;
495         pPalette = (unsigned char *)chipdata + sizeof(CHIP);
496         sizePalette = nColorCount * sizeof(pgchip_color);
497 
498         poDS->poColorTable = new GDALColorTable();
499 
500         for( int iColor = 0; iColor < nColorCount; iColor++ )
501         {
502             oEntry.c1 = pPalette[offsetColor++];
503             oEntry.c2 = pPalette[offsetColor++];
504             oEntry.c3 = pPalette[offsetColor++];
505             oEntry.c4 = pPalette[offsetColor++];
506 
507             poDS->poColorTable->SetColorEntry( iColor, &oEntry );
508         }
509     }
510 
511     return( poDS );
512 }
513 
514 
515 /************************************************************************/
516 /*                           PGCHIPCreateCopy()                         */
517 /************************************************************************/
PGCHIPCreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)518 static GDALDataset * PGCHIPCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
519                 int bStrict, char ** papszOptions,
520                 GDALProgressFunc pfnProgress, void * pProgressData ){
521 
522 
523     PGconn          *hPGConn;
524     char            *pszTableName = NULL;
525     const char      *pszDSName = NULL;
526     char*            pszCommand;
527     PGresult        *hResult;
528     char            *pszProjection;
529     int              SRID;
530     GDALColorTable  *poCT= NULL;
531     int              bTableExists = FALSE;
532     int              bHasNameCol = FALSE;
533 
534     int  nXSize = poSrcDS->GetRasterXSize();
535     int  nYSize = poSrcDS->GetRasterYSize();
536     int  nBands = poSrcDS->GetRasterCount();
537 
538 /* -------------------------------------------------------------------- */
539 /*      Some some rudimentary checks                                    */
540 /* -------------------------------------------------------------------- */
541 
542     /* check number of bands */
543     if( nBands != 1 && nBands != 4)
544     {
545         CPLError( CE_Failure, CPLE_NotSupported,
546                   "Under development : PGCHIP driver doesn't support %d bands.  Must be 1 or 4\n", nBands );
547 
548         return NULL;
549     }
550 
551     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
552         && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_UInt16)
553     {
554         CPLError( CE_Failure, CPLE_NotSupported,
555                   "Under development : PGCHIP driver doesn't support data type %s. "
556                   "Only eight bit (Byte) and sixteen bit (UInt16) bands supported.\n",
557                   GDALGetDataTypeName(
558                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
559 
560         return NULL;
561     }
562 
563     hPGConn = PGChipOpenConnection(pszFilename, &pszTableName, &pszDSName, FALSE, &bTableExists, &bHasNameCol);
564 
565     /* Check Postgis connection string */
566     if( hPGConn == NULL){
567         CPLError( CE_Failure, CPLE_NotSupported,
568                   "Cannont connect to %s.\n", pszFilename);
569         return NULL;
570     }
571 
572 /* -------------------------------------------------------------------- */
573 /*      Setup some parameters.                                          */
574 /* -------------------------------------------------------------------- */
575 
576     int nBitDepth;
577     GDALDataType eType;
578     int storageChunk;
579     int nColorType=0;
580 
581 
582     if( nBands == 1 && poSrcDS->GetRasterBand(1)->GetColorTable() == NULL ){
583         nColorType = PGCHIP_COLOR_TYPE_GRAY;
584     }
585     else if( nBands == 1 ){
586         nColorType = PGCHIP_COLOR_TYPE_PALETTE;
587     }
588     else if( nBands == 4 ){
589         nColorType = PGCHIP_COLOR_TYPE_RGB_ALPHA;
590     }
591 
592     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_UInt16 )
593     {
594         eType = GDT_Byte;
595         nBitDepth = 8;
596     }
597     else
598     {
599         eType = GDT_UInt16;
600         nBitDepth = 16;
601     }
602 
603     storageChunk = nBitDepth/8;
604 
605     //printf("nBands = %d, nBitDepth = %d\n",nBands,nBitDepth);
606 
607     pszCommand = (char*)CPLMalloc(1024);
608 
609     if(!bTableExists){
610         sprintf( pszCommand,
611                 "CREATE TABLE %s(raster chip, name varchar)",
612                 pszTableName);
613 
614         hResult = PQexec(hPGConn,pszCommand);
615         bHasNameCol = TRUE;
616     }
617     else
618     {
619         if (bHasNameCol)
620             sprintf( pszCommand,
621                     "DELETE FROM %s WHERE name = '%s'", pszTableName, pszDSName);
622         else
623             sprintf( pszCommand,
624                     "DELETE FROM %s", pszTableName);
625 
626         hResult = PQexec(hPGConn,pszCommand);
627     }
628 
629     if( hResult && (PQresultStatus(hResult) == PGRES_COMMAND_OK || PQresultStatus(hResult) == PGRES_TUPLES_OK)){
630         PQclear( hResult );
631     }
632     else {
633         CPLError( CE_Failure, CPLE_AppDefined,
634                   "%s", PQerrorMessage(hPGConn) );
635         PQfinish( hPGConn );
636         hPGConn = NULL;
637         return NULL;
638     }
639 
640 /* -------------------------------------------------------------------- */
641 /*      Projection, finding SRID                                        */
642 /* -------------------------------------------------------------------- */
643 
644     pszProjection = (char *)poSrcDS->GetProjectionRef();
645     SRID = -1;
646 
647     if( !EQUALN(pszProjection,"GEOGCS",6)
648         && !EQUALN(pszProjection,"PROJCS",6)
649         && !EQUALN(pszProjection,"+",6)
650         && !EQUAL(pszProjection,"") )
651     {
652         CPLError( CE_Failure, CPLE_AppDefined,
653                 "Only OGC WKT Projections supported for writing to Postgis.\n"
654                 "%s not supported.",
655                   pszProjection );
656     }
657 
658 
659     if( pszProjection[0]=='+')
660         sprintf( pszCommand,"SELECT SRID FROM spatial_ref_sys where proj4text=%s",pszProjection);
661     else
662         sprintf( pszCommand,"SELECT SRID FROM spatial_ref_sys where srtext=%s",pszProjection);
663 
664     hResult = PQexec(hPGConn,pszCommand);
665 
666     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
667              && PQntuples(hResult) > 0 ){
668 
669             SRID = atoi(PQgetvalue(hResult,0,0));
670 
671     }
672 
673     // Try to find SRID via EPSG number
674     if (SRID == -1 && strcmp(pszProjection,"") != 0){
675 
676             char *buf;
677             char epsg[16];
678             memset(epsg,0,16);
679             const char *workingproj = pszProjection;
680 
681             while( (buf = strstr(workingproj,"EPSG")) != 0){
682                 workingproj = buf+4;
683             }
684 
685             int iChar = 0;
686             workingproj = workingproj + 3;
687 
688 
689             while(workingproj[iChar] != '"' && iChar < 15){
690                 epsg[iChar] = workingproj[iChar];
691                 iChar++;
692             }
693 
694             if(epsg[0] != 0){
695                 SRID = atoi(epsg);
696             }
697     }
698     else{
699             CPLError( CE_Failure, CPLE_AppDefined,
700                 "Projection %s not found in spatial_ref_sys table. SRID will be set to -1.\n",
701                   pszProjection );
702 
703             SRID = -1;
704     }
705 
706     if( hResult )
707         PQclear( hResult );
708 
709 
710 /* -------------------------------------------------------------------- */
711 /*      Write palette if there is one.  Technically, I think it is      */
712 /*      possible to write 16bit palettes for PNG, but we will omit      */
713 /*      this for now.                                                   */
714 /* -------------------------------------------------------------------- */
715 
716     unsigned char	*pPalette = NULL;
717     int		bHaveNoData = FALSE;
718     double	dfNoDataValue = -1;
719     int nbColors = 0,bFoundTrans = FALSE;
720     size_t sizePalette = 0;
721 
722     if( nColorType == PGCHIP_COLOR_TYPE_PALETTE )
723     {
724 
725         GDALColorEntry  sEntry;
726         int		iColor;
727         int             offsetColor = -1;
728 
729         poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
730         nbColors = poCT->GetColorEntryCount();
731 
732         sizePalette += sizeof(pgchip_color) * poCT->GetColorEntryCount();
733 
734         pPalette = (unsigned char *) CPLMalloc(sizePalette);
735 
736 
737         for( iColor = 0; iColor < poCT->GetColorEntryCount(); iColor++ )
738         {
739             poCT->GetColorEntryAsRGB( iColor, &sEntry );
740             if( sEntry.c4 != 255 )
741                 bFoundTrans = TRUE;
742 
743             pPalette[offsetColor++]  = (unsigned char) sEntry.c1;
744             pPalette[offsetColor++]  = (unsigned char) sEntry.c2;
745             pPalette[offsetColor++]  = (unsigned char) sEntry.c3;
746 
747 
748             if( bHaveNoData && iColor == (int) dfNoDataValue ){
749                 pPalette[offsetColor++]  = 0;
750             }
751             else{
752                 pPalette[offsetColor++]  = (unsigned char) sEntry.c4;
753             }
754         }
755     }
756 
757 
758 /* -------------------------------------------------------------------- */
759 /*     Initialize CHIP Structure                                        */
760 /* -------------------------------------------------------------------- */
761 
762     CHIP PGCHIP;
763 
764     memset(&PGCHIP,0,sizeof(PGCHIP));
765 
766     PGCHIP.factor = 1.0;
767     PGCHIP.endian_hint = 1;
768     PGCHIP.compression = 0; // nbColors; // To cope with palette extra information  : <header><palette><data>
769     PGCHIP.height = nYSize;
770     PGCHIP.width = nXSize;
771     PGCHIP.SRID = SRID;
772     PGCHIP.future[0] = 0; // nBands; //nBands is stored in future variable
773     PGCHIP.future[1] = 0; // nBitDepth; //nBitDepth is stored in future variable
774     PGCHIP.future[2] = 0; // nColorType; //nBitDepth is stored in future variable
775     PGCHIP.future[3] = 0; // nbColors; // Useless as we store nbColors in the "compression" integer
776     PGCHIP.data = NULL; // Serialized Form
777 
778     double adfGeoTransform[6];
779     if (GDALGetGeoTransform(poSrcDS, adfGeoTransform) == CE_None)
780     {
781         if (adfGeoTransform[2] == 0 &&
782             adfGeoTransform[4] == 0 &&
783             adfGeoTransform[5] < 0)
784         {
785             PGCHIP.bvol.xmin = adfGeoTransform[0];
786             PGCHIP.bvol.ymax = adfGeoTransform[3];
787             PGCHIP.bvol.xmax = adfGeoTransform[0] + nXSize * adfGeoTransform[1];
788             PGCHIP.bvol.ymin = adfGeoTransform[3] + nYSize * adfGeoTransform[5];
789         }
790         else
791         {
792             CPLError( CE_Warning, CPLE_AppDefined,
793                       "Could not write geotransform.\n" );
794         }
795     }
796 
797     // PGCHIP.size changes if there is a palette.
798     // Is calculated by Postgis when inserting anyway
799     PGCHIP.size = sizeof(CHIP) - sizeof(void*) + (nYSize * nXSize * storageChunk * nBands) + sizePalette;
800 
801     switch(nBitDepth)
802     {
803         case 8:
804             PGCHIP.datatype = 8; // NDR|XDR ?
805             break;
806         case 16:
807             PGCHIP.datatype = 6; // NDR|XDR ?
808             break;
809         case 24:
810             PGCHIP.datatype = 5; // NDR|XDR ?
811             break;
812         default:
813              CPLError( CE_Failure, CPLE_AppDefined,"Under development : ERROR STORAGE CHUNK SIZE NOT SUPPORTED\n");
814             break;
815     }
816 
817 #ifdef PGCHIP_DEBUG
818     PGCHIPDataset::printChipInfo(PGCHIP);
819 #endif
820 
821 /* -------------------------------------------------------------------- */
822 /*      Loop over image                                                 */
823 /* -------------------------------------------------------------------- */
824 
825     CPLErr      eErr;
826     size_t lineSize = nXSize * storageChunk * nBands;
827 
828     // allocating data buffer
829     GByte *data = (GByte *) CPLMalloc( nYSize * lineSize);
830 
831     for( int iLine = 0; iLine < nYSize; iLine++ ){
832         for( int iBand = 0; iBand < nBands; iBand++ ){
833 
834             GDALRasterBand * poBand = poSrcDS->GetRasterBand( iBand+1 );
835 
836             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
837                                      data + (iBand*storageChunk) + iLine * lineSize,
838                                      nXSize, 1, eType,
839                                      nBands * storageChunk,
840                                      lineSize );
841          }
842     }
843 
844 
845 /* -------------------------------------------------------------------- */
846 /*      Write Header, Palette and Data                                  */
847 /* -------------------------------------------------------------------- */
848 
849     char *result;
850     size_t j=0;
851 
852     // Calculating result length (*2 -> Hex form, +1 -> end string)
853     size_t size_result = (PGCHIP.size * 2) + 1;
854 
855     // memory allocation
856     result = (char *) CPLMalloc( size_result * sizeof(char));
857 
858     // Assign chip
859     GByte *header = (GByte *)&PGCHIP;
860 
861     // Copy header into result string
862     for(j=0; j<sizeof(PGCHIP)-sizeof(void*); j++) {
863         pgch_deparse_hex( header[j], (unsigned char*)&(result[j*2]));
864     }
865 
866     // Copy Palette into result string if required
867     size_t offsetPalette = (sizeof(PGCHIP)-sizeof(void*)) * 2;
868     if(nColorType == PGCHIP_COLOR_TYPE_PALETTE && sizePalette>0){
869         for(j=0;j<sizePalette;j++){
870             pgch_deparse_hex( pPalette[j], (unsigned char *)&result[offsetPalette + (j*2)]);
871         }
872     }
873 
874     // Copy data into result string
875     size_t offsetData = offsetPalette + sizePalette * 2;
876     for(j=0;j<(nYSize * lineSize);j++){
877          pgch_deparse_hex( data[j], (unsigned char *)&result[offsetData + (j*2)]);
878     }
879 
880 
881     // end string
882     result[offsetData + j*2] = '\0';
883 
884 
885 /* -------------------------------------------------------------------- */
886 /*      Inserting Chip                                                  */
887 /* -------------------------------------------------------------------- */
888 
889     // Second allocation to cope with data size
890     CPLFree(pszCommand);
891     pszCommand = (char *)CPLMalloc(PGCHIP.size*2 + 256);
892 
893     hResult = PQexec(hPGConn, "BEGIN");
894 
895     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
896     {
897 
898         PQclear( hResult );
899         if (bHasNameCol)
900             sprintf( pszCommand,
901                     "INSERT INTO %s(raster, name) values('%s', '%s')",
902                     pszTableName,result, pszDSName);
903         else
904             sprintf( pszCommand,
905                     "INSERT INTO %s(raster) values('%s')",
906                     pszTableName,result);
907 
908 
909         hResult = PQexec(hPGConn,pszCommand);
910 
911     }
912 
913     CPLFree(pszTableName); pszTableName = NULL;
914 
915     if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK ){
916         PQclear( hResult );
917     }
918     else {
919         CPLError( CE_Failure, CPLE_AppDefined,
920                   "%s", PQerrorMessage(hPGConn) );
921         CPLFree(pszCommand); pszCommand = NULL;
922         PQfinish( hPGConn );
923         hPGConn = NULL;
924         return NULL;
925     }
926 
927     hResult = PQexec(hPGConn, "COMMIT");
928     PQclear( hResult );
929 
930     CPLFree( pszCommand ); pszCommand = NULL;
931     CPLFree( pPalette ); pPalette = NULL;
932     CPLFree( data ); data = NULL;
933     CPLFree( result ); result = NULL;
934 
935     PQfinish( hPGConn );
936     hPGConn = NULL;
937 
938     return (GDALDataset *)GDALOpen(pszFilename,GA_Update);
939 }
940 
941 
942 /************************************************************************/
943 /*                          Display CHIP information                    */
944 /************************************************************************/
printChipInfo(const CHIP & c)945 void     PGCHIPDataset::printChipInfo(const CHIP& c){
946 
947     //if(this->PGCHIP != NULL){
948         printf("\n---< CHIP INFO >----\n");
949         printf("CHIP.datatype = %d\n", c.datatype);
950         printf("CHIP.compression = %d\n", c.compression);
951         printf("CHIP.size = %d\n", c.size);
952         printf("CHIP.factor = %f\n", c.factor);
953         printf("CHIP.width = %d\n", c.width);
954         printf("CHIP.height = %d\n", c.height);
955         //printf("CHIP.future[0] (nBands?) = %d\n", (int)c.future[0]);
956         //printf("CHIP.future[1] (nBitDepth?) = %d\n", (int)c.future[1]);
957         printf("--------------------\n");
958      //}
959 }
960 
961 /************************************************************************/
962 /*                              PGCHIPDelete                            */
963 /************************************************************************/
PGCHIPDelete(const char * pszFilename)964 static CPLErr PGCHIPDelete(const char* pszFilename)
965 {
966     return CE_None;
967 }
968 
969 /************************************************************************/
970 /*                          GDALRegister_PGCHIP()                       */
971 /************************************************************************/
GDALRegister_PGCHIP()972 void GDALRegister_PGCHIP(){
973 
974     GDALDriver	*poDriver;
975 
976     if( GDALGetDriverByName( "PGCHIP" ) == NULL )
977     {
978         poDriver = new GDALDriver();
979 
980         poDriver->SetDescription( "PGCHIP" );
981         poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
982         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
983                                    "Postgis CHIP raster" );
984 
985         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
986                                    "Byte UInt16" );
987 
988         poDriver->pfnOpen = PGCHIPDataset::Open;
989         poDriver->pfnCreateCopy = PGCHIPCreateCopy;
990         poDriver->pfnDelete = PGCHIPDelete;
991 
992         GetGDALDriverManager()->RegisterDriver( poDriver );
993     }
994 }
995 
996