mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 14:16:10 -06:00
6089 lines
206 KiB
C++
6089 lines
206 KiB
C++
/******************************************************************************
|
|
* $Id: gdalclientserver.cpp 28899 2015-04-14 09:27:00Z rouault $
|
|
*
|
|
* Project: GDAL Core
|
|
* Purpose: GDAL Client/server dataset mechanism.
|
|
* Author: Even Rouault, <even dot rouault at mines-paris dot org>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "cpl_port.h"
|
|
|
|
#ifdef WIN32
|
|
#ifdef _WIN32_WINNT
|
|
#undef _WIN32_WINNT
|
|
#endif
|
|
#define _WIN32_WINNT 0x0501
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
typedef SOCKET CPL_SOCKET;
|
|
#ifndef HAVE_GETADDRINFO
|
|
#define HAVE_GETADDRINFO 1
|
|
#endif
|
|
#else
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
typedef int CPL_SOCKET;
|
|
#define INVALID_SOCKET -1
|
|
#define SOCKET_ERROR -1
|
|
#define SOCKADDR struct sockaddr
|
|
#define WSAGetLastError() errno
|
|
#define WSACleanup()
|
|
#define closesocket(s) close(s)
|
|
#endif
|
|
|
|
#include "gdal_pam.h"
|
|
#include "gdal_rat.h"
|
|
#include "cpl_spawn.h"
|
|
#include "cpl_multiproc.h"
|
|
|
|
/*!
|
|
\page gdal_api_proxy GDAL API Proxy
|
|
|
|
\section gdal_api_proxy_intro Introduction
|
|
|
|
(GDAL >= 1.10.0)
|
|
|
|
When dealing with some file formats, particularly the drivers relying on third-party
|
|
(potentially closed-source) libraries, it is difficult to ensure that those third-party
|
|
libraries will be robust to hostile/corrupted datasource.
|
|
|
|
The implemented solution is to have a (private) API_PROXY driver that will expose a GDALClientDataset
|
|
object, which will forward all the GDAL API calls to another process ("server"), where the real driver
|
|
will be effectively run. This way, if the server aborts due to a fatal error, the calling process will
|
|
be unaffected and will report a clean error instead of aborting itself.
|
|
|
|
\section gdal_api_proxy_enabling How to enable ?
|
|
|
|
The API_PROXY mechanism can be enabled by setting the GDAL_API_PROXY config option to YES.
|
|
The option can also be set to a list of file extensions that must be the only ones to trigger
|
|
this mechanism (e.g. GDAL_API_PROXY=ecw,sid).
|
|
|
|
When enabled, datasets can be handled with GDALOpen(), GDALCreate() or GDALCreateCopy() with
|
|
their nominal filename (or connexion string).
|
|
|
|
Alternatively, the API_PROXY mechanism can be used selectively on a datasource by prefixing its
|
|
name with API_PROXY:, for example GDALOpen("API_PROXY:foo.tif", GA_ReadOnly).
|
|
|
|
\section gdal_api_proxy_options Advanced options
|
|
|
|
For now, the server launched is the gdalserver executable on Windows. On Unix, the default behaviour is
|
|
to just fork() the current process. It is also possible to launch the gdalserver executable
|
|
by forcing GDAL_API_PROXY_SERVER=YES.
|
|
The full filename of the gdalserver executable can also be specified in the GDAL_API_PROXY_SERVER.
|
|
|
|
It is also possible to connect to a gdalserver in TCP, possibly on a remote host. In that case,
|
|
gdalserver must be launched on a host with "gdalserver -tcpserver the_tcp_port". And the client
|
|
must set GDAL_API_PROXY_SERVER="hostname:the_tcp_port", where hostname is a string or a IP address.
|
|
|
|
In case of many dataset opening or creation, to avoid the cost of repeated process forking,
|
|
a pool of unused connections is established. Each time a dataset is closed, the associated connection
|
|
is pushed in the pool (if there's an empty bucket). When a following dataset is to be opened, one of those
|
|
connections will be reused. This behaviour is controlled with the GDAL_API_PROXY_CONN_POOL config option
|
|
that is set to YES by default, and will keep a maximum of 4 unused connections.
|
|
GDAL_API_PROXY_CONN_POOL can be set to a integer value to specify the maximum number of unused connections.
|
|
|
|
\section gdal_api_proxy_limitations Limitations
|
|
|
|
Datasets stored in the memory virtual file system (/vsimem) or handled by the MEM driver are excluded from
|
|
the API Proxy mechanism.
|
|
|
|
Additionnaly, for GDALCreate() or GDALCreateCopy(), the VRT driver is also excluded from that mechanism.
|
|
|
|
Currently, the client dataset returned is not protected by a mutex, so it is unsafe to use it concurrently
|
|
from multiple threads. However, it is safe to use several client datasets from multiple threads.
|
|
|
|
*/
|
|
|
|
/* REMINDER: upgrade this number when the on-wire protocol changes */
|
|
/* Note: please at least keep the version exchange protocol unchanged ! */
|
|
#define GDAL_CLIENT_SERVER_PROTOCOL_MAJOR 2
|
|
#define GDAL_CLIENT_SERVER_PROTOCOL_MINOR 0
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
CPL_C_START
|
|
int CPL_DLL GDALServerLoop(CPL_FILE_HANDLE fin, CPL_FILE_HANDLE fout);
|
|
const char* GDALClientDatasetGetFilename(const char* pszFilename);
|
|
int CPL_DLL GDALServerLoopSocket(CPL_SOCKET nSocket);
|
|
CPL_C_END
|
|
|
|
#define BUFFER_SIZE 1024
|
|
typedef struct
|
|
{
|
|
CPL_FILE_HANDLE fin;
|
|
CPL_FILE_HANDLE fout;
|
|
CPL_SOCKET nSocket;
|
|
int bOK;
|
|
GByte abyBuffer[BUFFER_SIZE];
|
|
int nBufferSize;
|
|
} GDALPipe;
|
|
|
|
typedef struct
|
|
{
|
|
CPLSpawnedProcess *sp;
|
|
GDALPipe *p;
|
|
} GDALServerSpawnedProcess;
|
|
|
|
typedef struct
|
|
{
|
|
int bUpdated;
|
|
double dfComplete;
|
|
char *pszProgressMsg;
|
|
int bRet;
|
|
CPLMutex *hMutex;
|
|
} GDALServerAsyncProgress;
|
|
|
|
typedef enum
|
|
{
|
|
INSTR_INVALID = 0,
|
|
INSTR_GetGDALVersion = 1, /* do not change this ! */
|
|
INSTR_EXIT,
|
|
INSTR_EXIT_FAIL,
|
|
INSTR_SetConfigOption,
|
|
INSTR_Progress,
|
|
INSTR_Reset,
|
|
INSTR_Open,
|
|
INSTR_Identify,
|
|
INSTR_Create,
|
|
INSTR_CreateCopy,
|
|
INSTR_QuietDelete,
|
|
INSTR_AddBand,
|
|
INSTR_GetGeoTransform,
|
|
INSTR_SetGeoTransform,
|
|
INSTR_GetProjectionRef,
|
|
INSTR_SetProjection,
|
|
INSTR_GetGCPCount,
|
|
INSTR_GetGCPProjection,
|
|
INSTR_GetGCPs,
|
|
INSTR_SetGCPs,
|
|
INSTR_GetFileList,
|
|
INSTR_FlushCache,
|
|
INSTR_SetDescription,
|
|
INSTR_GetMetadata,
|
|
INSTR_GetMetadataItem,
|
|
INSTR_SetMetadata,
|
|
INSTR_SetMetadataItem,
|
|
INSTR_IRasterIO_Read,
|
|
INSTR_IRasterIO_Write,
|
|
INSTR_IBuildOverviews,
|
|
INSTR_AdviseRead,
|
|
INSTR_CreateMaskBand,
|
|
INSTR_Band_First,
|
|
INSTR_Band_FlushCache,
|
|
INSTR_Band_GetCategoryNames,
|
|
INSTR_Band_SetCategoryNames,
|
|
INSTR_Band_SetDescription,
|
|
INSTR_Band_GetMetadata,
|
|
INSTR_Band_GetMetadataItem,
|
|
INSTR_Band_SetMetadata,
|
|
INSTR_Band_SetMetadataItem,
|
|
INSTR_Band_GetColorInterpretation,
|
|
INSTR_Band_SetColorInterpretation,
|
|
INSTR_Band_GetNoDataValue,
|
|
INSTR_Band_GetMinimum,
|
|
INSTR_Band_GetMaximum,
|
|
INSTR_Band_GetOffset,
|
|
INSTR_Band_GetScale,
|
|
INSTR_Band_SetNoDataValue,
|
|
INSTR_Band_SetOffset,
|
|
INSTR_Band_SetScale,
|
|
INSTR_Band_IReadBlock,
|
|
INSTR_Band_IWriteBlock,
|
|
INSTR_Band_IRasterIO_Read,
|
|
INSTR_Band_IRasterIO_Write,
|
|
INSTR_Band_GetStatistics,
|
|
INSTR_Band_ComputeStatistics,
|
|
INSTR_Band_SetStatistics,
|
|
INSTR_Band_ComputeRasterMinMax,
|
|
INSTR_Band_GetHistogram,
|
|
INSTR_Band_GetDefaultHistogram,
|
|
INSTR_Band_SetDefaultHistogram,
|
|
INSTR_Band_HasArbitraryOverviews,
|
|
INSTR_Band_GetOverviewCount,
|
|
INSTR_Band_GetOverview,
|
|
INSTR_Band_GetMaskBand,
|
|
INSTR_Band_GetMaskFlags,
|
|
INSTR_Band_CreateMaskBand,
|
|
INSTR_Band_Fill,
|
|
INSTR_Band_GetColorTable,
|
|
INSTR_Band_SetColorTable,
|
|
INSTR_Band_GetUnitType,
|
|
INSTR_Band_SetUnitType,
|
|
INSTR_Band_BuildOverviews,
|
|
INSTR_Band_GetDefaultRAT,
|
|
INSTR_Band_SetDefaultRAT,
|
|
INSTR_Band_AdviseRead,
|
|
INSTR_Band_End,
|
|
INSTR_END
|
|
} InstrEnum;
|
|
|
|
#ifdef DEBUG
|
|
static const char* apszInstr[] =
|
|
{
|
|
"INVALID",
|
|
"GetGDALVersion",
|
|
"EXIT",
|
|
"FAIL",
|
|
"SetConfigOption",
|
|
"Progress",
|
|
"Reset",
|
|
"Open",
|
|
"Identify",
|
|
"Create",
|
|
"CreateCopy",
|
|
"QuietDelete",
|
|
"AddBand",
|
|
"GetGeoTransform",
|
|
"SetGeoTransform",
|
|
"GetProjectionRef",
|
|
"SetProjection",
|
|
"GetGCPCount",
|
|
"GetGCPProjection",
|
|
"GetGCPs",
|
|
"SetGCPs",
|
|
"GetFileList",
|
|
"FlushCache",
|
|
"SetDescription",
|
|
"GetMetadata",
|
|
"GetMetadataItem",
|
|
"SetMetadata",
|
|
"SetMetadataItem",
|
|
"IRasterIO_Read",
|
|
"IRasterIO_Write",
|
|
"IBuildOverviews",
|
|
"AdviseRead",
|
|
"CreateMaskBand",
|
|
"Band_First",
|
|
"Band_FlushCache",
|
|
"Band_GetCategoryNames",
|
|
"Band_SetCategoryNames",
|
|
"Band_SetDescription",
|
|
"Band_GetMetadata",
|
|
"Band_GetMetadataItem",
|
|
"Band_SetMetadata",
|
|
"Band_SetMetadataItem",
|
|
"Band_GetColorInterpretation",
|
|
"Band_SetColorInterpretation",
|
|
"Band_GetNoDataValue",
|
|
"Band_GetMinimum",
|
|
"Band_GetMaximum",
|
|
"Band_GetOffset",
|
|
"Band_GetScale",
|
|
"Band_SetNoDataValue",
|
|
"Band_SetOffset",
|
|
"Band_SetScale",
|
|
"Band_IReadBlock",
|
|
"Band_IWriteBlock",
|
|
"Band_IRasterIO_Read",
|
|
"Band_IRasterIO_Write",
|
|
"Band_GetStatistics",
|
|
"Band_ComputeStatistics",
|
|
"Band_SetStatistics",
|
|
"Band_ComputeRasterMinMax",
|
|
"Band_GetHistogram",
|
|
"Band_GetDefaultHistogram",
|
|
"Band_SetDefaultHistogram",
|
|
"Band_HasArbitraryOverviews",
|
|
"Band_GetOverviewCount",
|
|
"Band_GetOverview",
|
|
"Band_GetMaskBand",
|
|
"Band_GetMaskFlags",
|
|
"Band_CreateMaskBand",
|
|
"Band_Fill",
|
|
"Band_GetColorTable",
|
|
"Band_SetColorTable",
|
|
"Band_GetUnitType",
|
|
"Band_SetUnitType",
|
|
"Band_BuildOverviews",
|
|
"Band_GetDefaultRAT",
|
|
"Band_SetDefaultRAT",
|
|
"Band_AdviseRead",
|
|
"Band_End",
|
|
"END",
|
|
};
|
|
#endif
|
|
|
|
static const GByte abyEndOfJunkMarker[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
|
|
|
/* Recycling of connexions to child processes */
|
|
#define MAX_RECYCLED 128
|
|
#define DEFAULT_RECYCLED 4
|
|
static int bRecycleChild = FALSE;
|
|
static int nMaxRecycled = 0;
|
|
static GDALServerSpawnedProcess* aspRecycled[MAX_RECYCLED];
|
|
|
|
/************************************************************************/
|
|
/* EnterObject */
|
|
/************************************************************************/
|
|
|
|
#ifdef DEBUG_VERBOSE
|
|
class EnterObject
|
|
{
|
|
const char* pszFunction;
|
|
|
|
public:
|
|
EnterObject(const char* pszFunction) : pszFunction(pszFunction)
|
|
{
|
|
CPLDebug("GDAL", "Enter %s", pszFunction);
|
|
}
|
|
|
|
~EnterObject()
|
|
{
|
|
CPLDebug("GDAL", "Leave %s", pszFunction);
|
|
}
|
|
};
|
|
|
|
#define CLIENT_ENTER() EnterObject o(__FUNCTION__)
|
|
#else
|
|
#define CLIENT_ENTER() while(0)
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* MyChdir() */
|
|
/************************************************************************/
|
|
|
|
static void MyChdir(
|
|
#ifndef WIN32
|
|
CPL_UNUSED
|
|
#endif
|
|
const char* pszCWD)
|
|
{
|
|
#ifdef WIN32
|
|
SetCurrentDirectory(pszCWD);
|
|
#else
|
|
CPLAssert(chdir(pszCWD) == 0);
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* MyChdirRootDirectory() */
|
|
/************************************************************************/
|
|
|
|
static void MyChdirRootDirectory()
|
|
{
|
|
#ifdef WIN32
|
|
SetCurrentDirectory("C:\\");
|
|
#else
|
|
CPLAssert(chdir("/") == 0);
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALClientDataset */
|
|
/************************************************************************/
|
|
|
|
class GDALClientDataset: public GDALPamDataset
|
|
{
|
|
GDALServerSpawnedProcess *ssp;
|
|
GDALPipe *p;
|
|
CPLString osProjection;
|
|
CPLString osGCPProjection;
|
|
int bFreeDriver;
|
|
int nGCPCount;
|
|
GDAL_GCP *pasGCPs;
|
|
std::map<CPLString, char**> aoMapMetadata;
|
|
std::map< std::pair<CPLString,CPLString>, char*> aoMapMetadataItem;
|
|
GDALServerAsyncProgress *async;
|
|
GByte abyCaps[16]; /* 16 * 8 = 128 > INSTR_END */
|
|
|
|
int mCreateCopy(const char* pszFilename,
|
|
GDALDataset* poSrcDS,
|
|
int bStrict, char** papszOptions,
|
|
GDALProgressFunc pfnProgress,
|
|
void * pProgressData);
|
|
int mCreate( const char * pszName,
|
|
int nXSize, int nYSize, int nBands,
|
|
GDALDataType eType,
|
|
char ** papszOptions );
|
|
|
|
GDALClientDataset(GDALServerSpawnedProcess* ssp);
|
|
|
|
static GDALClientDataset* CreateAndConnect();
|
|
|
|
protected:
|
|
virtual CPLErr IBuildOverviews( const char *, int, int *,
|
|
int, int *, GDALProgressFunc, void * );
|
|
virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
int nBandCount, int *panBandMap,
|
|
GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
|
|
GDALRasterIOExtraArg* psExtraArg);
|
|
public:
|
|
GDALClientDataset(GDALPipe* p);
|
|
~GDALClientDataset();
|
|
|
|
int Init(const char* pszFilename, GDALAccess eAccess);
|
|
|
|
void AttachAsyncProgress(GDALServerAsyncProgress* async) { this->async = async; }
|
|
int ProcessAsyncProgress();
|
|
int SupportsInstr(InstrEnum instr) const { return abyCaps[instr / 8] & (1 << (instr % 8)); }
|
|
|
|
virtual void FlushCache();
|
|
|
|
virtual CPLErr AddBand( GDALDataType eType,
|
|
char **papszOptions=NULL );
|
|
|
|
//virtual void SetDescription( const char * );
|
|
|
|
virtual const char* GetMetadataItem( const char * pszName,
|
|
const char * pszDomain = "" );
|
|
virtual char **GetMetadata( const char * pszDomain = "" );
|
|
virtual CPLErr SetMetadata( char ** papszMetadata,
|
|
const char * pszDomain = "" );
|
|
virtual CPLErr SetMetadataItem( const char * pszName,
|
|
const char * pszValue,
|
|
const char * pszDomain = "" );
|
|
|
|
virtual const char* GetProjectionRef();
|
|
virtual CPLErr SetProjection( const char * );
|
|
|
|
virtual CPLErr GetGeoTransform( double * );
|
|
virtual CPLErr SetGeoTransform( double * );
|
|
|
|
virtual int GetGCPCount();
|
|
virtual const char *GetGCPProjection();
|
|
virtual const GDAL_GCP *GetGCPs();
|
|
virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
|
|
const char *pszGCPProjection );
|
|
|
|
virtual char **GetFileList(void);
|
|
|
|
virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
|
|
int nBufXSize, int nBufYSize,
|
|
GDALDataType eDT,
|
|
int nBandCount, int *panBandList,
|
|
char **papszOptions );
|
|
|
|
virtual CPLErr CreateMaskBand( int nFlags );
|
|
|
|
static GDALDataset *Open( GDALOpenInfo * );
|
|
static int Identify( GDALOpenInfo * );
|
|
static GDALDataset *CreateCopy( const char * pszFilename,
|
|
GDALDataset * poSrcDS, int bStrict, char ** papszOptions,
|
|
GDALProgressFunc pfnProgress, void * pProgressData );
|
|
static GDALDataset* Create( const char * pszName,
|
|
int nXSize, int nYSize, int nBands,
|
|
GDALDataType eType,
|
|
char ** papszOptions );
|
|
static CPLErr Delete( const char * pszName );
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALClientRasterBand */
|
|
/************************************************************************/
|
|
|
|
class GDALClientRasterBand : public GDALPamRasterBand
|
|
{
|
|
friend class GDALClientDataset;
|
|
|
|
GDALPipe *p;
|
|
int iSrvBand;
|
|
std::map<int, GDALRasterBand*> aMapOvrBands;
|
|
std::map<int, GDALRasterBand*> aMapOvrBandsCurrent;
|
|
GDALRasterBand *poMaskBand;
|
|
std::map<CPLString, char**> aoMapMetadata;
|
|
std::map< std::pair<CPLString,CPLString>, char*> aoMapMetadataItem;
|
|
char **papszCategoryNames;
|
|
GDALColorTable *poColorTable;
|
|
char *pszUnitType;
|
|
GDALRasterAttributeTable *poRAT;
|
|
std::vector<GDALRasterBand*> apoOldMaskBands;
|
|
GByte abyCaps[16]; /* 16 * 8 = 128 > INSTR_END */
|
|
|
|
int WriteInstr(InstrEnum instr);
|
|
|
|
double GetDouble( InstrEnum instr, int *pbSuccess );
|
|
CPLErr SetDouble( InstrEnum instr, double dfVal );
|
|
|
|
GDALRasterBand *CreateFakeMaskBand();
|
|
|
|
int bEnableLineCaching;
|
|
int nSuccessiveLinesRead;
|
|
GDALDataType eLastBufType;
|
|
int nLastYOff;
|
|
GByte *pabyCachedLines;
|
|
GDALDataType eCachedBufType;
|
|
int nCachedYStart;
|
|
int nCachedLines;
|
|
|
|
void InvalidateCachedLines();
|
|
CPLErr IRasterIO_read_internal(
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
GSpacing nPixelSpace, GSpacing nLineSpace );
|
|
protected:
|
|
|
|
virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void* pImage);
|
|
virtual CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void* pImage);
|
|
virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
GSpacing nPixelSpace, GSpacing nLineSpace,
|
|
GDALRasterIOExtraArg* psExtraArg);
|
|
|
|
public:
|
|
GDALClientRasterBand(GDALPipe* p, int iSrvBand,
|
|
GDALClientDataset* poDS, int nBand, GDALAccess eAccess,
|
|
int nRasterXSize, int nRasterYSize,
|
|
GDALDataType eDataType, int nBlockXSize, int nBlockYSize,
|
|
GByte abyCaps[16]);
|
|
~GDALClientRasterBand();
|
|
|
|
int GetSrvBand() const { return iSrvBand; }
|
|
int SupportsInstr(InstrEnum instr) const { return abyCaps[instr / 8] & (1 << (instr % 8)); }
|
|
|
|
void ClearOverviewCache() { aMapOvrBandsCurrent.clear(); }
|
|
|
|
virtual CPLErr FlushCache();
|
|
|
|
virtual void SetDescription( const char * );
|
|
|
|
virtual const char* GetMetadataItem( const char * pszName,
|
|
const char * pszDomain = "" );
|
|
virtual char **GetMetadata( const char * pszDomain = "" );
|
|
virtual CPLErr SetMetadata( char ** papszMetadata,
|
|
const char * pszDomain = "" );
|
|
virtual CPLErr SetMetadataItem( const char * pszName,
|
|
const char * pszValue,
|
|
const char * pszDomain = "" );
|
|
|
|
virtual GDALColorInterp GetColorInterpretation();
|
|
virtual CPLErr SetColorInterpretation( GDALColorInterp );
|
|
|
|
virtual char **GetCategoryNames();
|
|
virtual double GetNoDataValue( int *pbSuccess = NULL );
|
|
virtual double GetMinimum( int *pbSuccess = NULL );
|
|
virtual double GetMaximum(int *pbSuccess = NULL );
|
|
virtual double GetOffset( int *pbSuccess = NULL );
|
|
virtual double GetScale( int *pbSuccess = NULL );
|
|
|
|
virtual GDALColorTable *GetColorTable();
|
|
virtual CPLErr SetColorTable( GDALColorTable * );
|
|
|
|
virtual const char *GetUnitType();
|
|
virtual CPLErr SetUnitType( const char * );
|
|
|
|
virtual CPLErr Fill(double dfRealValue, double dfImaginaryValue = 0);
|
|
|
|
virtual CPLErr SetCategoryNames( char ** );
|
|
virtual CPLErr SetNoDataValue( double );
|
|
virtual CPLErr SetOffset( double );
|
|
virtual CPLErr SetScale( double );
|
|
|
|
virtual CPLErr GetStatistics( int bApproxOK, int bForce,
|
|
double *pdfMin, double *pdfMax,
|
|
double *pdfMean, double *padfStdDev );
|
|
virtual CPLErr ComputeStatistics( int bApproxOK,
|
|
double *pdfMin, double *pdfMax,
|
|
double *pdfMean, double *pdfStdDev,
|
|
GDALProgressFunc, void *pProgressData );
|
|
virtual CPLErr SetStatistics( double dfMin, double dfMax,
|
|
double dfMean, double dfStdDev );
|
|
virtual CPLErr ComputeRasterMinMax( int, double* );
|
|
|
|
virtual CPLErr GetHistogram( double dfMin, double dfMax,
|
|
int nBuckets, GUIntBig *panHistogram,
|
|
int bIncludeOutOfRange, int bApproxOK,
|
|
GDALProgressFunc pfnProgress,
|
|
void *pProgressData );
|
|
|
|
virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
|
|
int *pnBuckets, GUIntBig ** ppanHistogram,
|
|
int bForce,
|
|
GDALProgressFunc, void *pProgressData);
|
|
virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
|
|
int nBuckets, GUIntBig *panHistogram );
|
|
|
|
virtual int HasArbitraryOverviews();
|
|
virtual int GetOverviewCount();
|
|
virtual GDALRasterBand *GetOverview(int);
|
|
|
|
virtual GDALRasterBand *GetMaskBand();
|
|
virtual int GetMaskFlags();
|
|
virtual CPLErr CreateMaskBand( int nFlags );
|
|
|
|
virtual CPLErr BuildOverviews( const char *, int, int *,
|
|
GDALProgressFunc, void * );
|
|
|
|
virtual GDALRasterAttributeTable *GetDefaultRAT();
|
|
virtual CPLErr SetDefaultRAT( const GDALRasterAttributeTable * );
|
|
|
|
virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
|
|
int nBufXSize, int nBufYSize,
|
|
GDALDataType eDT, char **papszOptions );
|
|
/*
|
|
virtual GDALRasterBand *GetRasterSampleOverview( GUIntBig );
|
|
*/
|
|
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeBuild() */
|
|
/************************************************************************/
|
|
|
|
static GDALPipe* GDALPipeBuild(CPLSpawnedProcess* sp)
|
|
{
|
|
GDALPipe* p = (GDALPipe*)CPLMalloc(sizeof(GDALPipe));
|
|
p->bOK = TRUE;
|
|
p->fin = CPLSpawnAsyncGetInputFileHandle(sp);
|
|
p->fout = CPLSpawnAsyncGetOutputFileHandle(sp);
|
|
p->nSocket = INVALID_SOCKET;
|
|
p->nBufferSize = 0;
|
|
return p;
|
|
}
|
|
|
|
static GDALPipe* GDALPipeBuild(CPL_SOCKET nSocket)
|
|
{
|
|
GDALPipe* p = (GDALPipe*)CPLMalloc(sizeof(GDALPipe));
|
|
p->bOK = TRUE;
|
|
p->fin = CPL_FILE_INVALID_HANDLE;
|
|
p->fout = CPL_FILE_INVALID_HANDLE;
|
|
p->nSocket = nSocket;
|
|
p->nBufferSize = 0;
|
|
return p;
|
|
}
|
|
|
|
static GDALPipe* GDALPipeBuild(CPL_FILE_HANDLE fin, CPL_FILE_HANDLE fout)
|
|
{
|
|
GDALPipe* p = (GDALPipe*)CPLMalloc(sizeof(GDALPipe));
|
|
p->bOK = TRUE;
|
|
p->fin = fin;
|
|
p->fout = fout;
|
|
p->nSocket = INVALID_SOCKET;
|
|
p->nBufferSize = 0;
|
|
return p;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeWrite_internal() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeWrite_internal(GDALPipe* p, const void* data, int length)
|
|
{
|
|
if(!p->bOK)
|
|
return FALSE;
|
|
if( p->fout != CPL_FILE_INVALID_HANDLE )
|
|
{
|
|
int nRet = CPLPipeWrite(p->fout, data, length);
|
|
if( !nRet )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Write to pipe failed");
|
|
p->bOK = FALSE;
|
|
}
|
|
return nRet;
|
|
}
|
|
else
|
|
{
|
|
const char* pabyData = (const char*) data;
|
|
int nRemain = length;
|
|
while( nRemain > 0 )
|
|
{
|
|
int nRet = send(p->nSocket, pabyData, nRemain, 0);
|
|
if( nRet < 0 )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Write to socket failed");
|
|
p->bOK = FALSE;
|
|
return FALSE;
|
|
}
|
|
pabyData += nRet;
|
|
nRemain -= nRet;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeFlushBuffer() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeFlushBuffer(GDALPipe * p)
|
|
{
|
|
if( p->nBufferSize == 0 )
|
|
return TRUE;
|
|
if( GDALPipeWrite_internal(p, p->abyBuffer, p->nBufferSize) )
|
|
{
|
|
p->nBufferSize = 0;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeFree() */
|
|
/************************************************************************/
|
|
|
|
static void GDALPipeFree(GDALPipe * p)
|
|
{
|
|
GDALPipeFlushBuffer(p);
|
|
if( p->nSocket != INVALID_SOCKET )
|
|
{
|
|
closesocket(p->nSocket);
|
|
WSACleanup();
|
|
}
|
|
CPLFree(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeRead() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeRead(GDALPipe* p, void* data, int length)
|
|
{
|
|
if(!p->bOK)
|
|
return FALSE;
|
|
if(!GDALPipeFlushBuffer(p))
|
|
return FALSE;
|
|
|
|
if( p->fout != CPL_FILE_INVALID_HANDLE )
|
|
{
|
|
if( CPLPipeRead(p->fin, data, length) )
|
|
return TRUE;
|
|
// fprintf(stderr, "[%d] Read from pipe failed\n", (int)getpid());
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Read from pipe failed");
|
|
p->bOK = FALSE;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
char* pabyData = (char*) data;
|
|
int nRemain = length;
|
|
while( nRemain > 0 )
|
|
{
|
|
int nRet = recv(p->nSocket, pabyData, nRemain, 0);
|
|
if( nRet <= 0 )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Read from socket failed");
|
|
p->bOK = FALSE;
|
|
return FALSE;
|
|
}
|
|
pabyData += nRet;
|
|
nRemain -= nRet;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeWrite() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, const void* data,
|
|
int length)
|
|
{
|
|
//return GDALPipeWrite_internal(p, data, length);
|
|
GByte* pCur = (GByte*) data;
|
|
int nRemain = length;
|
|
while( nRemain > 0 )
|
|
{
|
|
if( p->nBufferSize + nRemain <= BUFFER_SIZE )
|
|
{
|
|
memcpy(p->abyBuffer + p->nBufferSize, pCur, nRemain);
|
|
pCur += nRemain;
|
|
p->nBufferSize += nRemain;
|
|
nRemain = 0;
|
|
}
|
|
else if( nRemain > BUFFER_SIZE )
|
|
{
|
|
if( !GDALPipeFlushBuffer(p) )
|
|
return FALSE;
|
|
if( !GDALPipeWrite_internal(p, pCur, nRemain) )
|
|
return FALSE;
|
|
pCur += nRemain;
|
|
nRemain = 0;
|
|
}
|
|
else
|
|
{
|
|
memcpy(p->abyBuffer + p->nBufferSize, pCur,
|
|
BUFFER_SIZE - p->nBufferSize);
|
|
pCur += (BUFFER_SIZE - p->nBufferSize);
|
|
nRemain -= (BUFFER_SIZE - p->nBufferSize);
|
|
p->nBufferSize = BUFFER_SIZE;
|
|
if( !GDALPipeFlushBuffer(p) )
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeRead() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeRead(GDALPipe* p, int* pnInt)
|
|
{
|
|
return GDALPipeRead(p, pnInt, 4);
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, GIntBig* pnInt)
|
|
{
|
|
return GDALPipeRead(p, pnInt, 8);
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, CPLErr* peErr)
|
|
{
|
|
return GDALPipeRead(p, peErr, 4);
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, double* pdfDouble)
|
|
{
|
|
return GDALPipeRead(p, pdfDouble, 8);
|
|
}
|
|
|
|
static int GDALPipeRead_nolength(GDALPipe* p, int nLength, void* pabyData)
|
|
{
|
|
return GDALPipeRead(p, pabyData, nLength);
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, int nExpectedLength, void* pabyData)
|
|
{
|
|
int nLength;
|
|
return GDALPipeRead(p, &nLength) &&
|
|
nLength == nExpectedLength &&
|
|
GDALPipeRead_nolength(p, nLength, pabyData);
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, char** ppszStr)
|
|
{
|
|
int nLength;
|
|
if( !GDALPipeRead(p, &nLength) || nLength < 0 )
|
|
{
|
|
*ppszStr = NULL;
|
|
return FALSE;
|
|
}
|
|
if( nLength == 0 )
|
|
{
|
|
*ppszStr = NULL;
|
|
return TRUE;
|
|
}
|
|
*ppszStr = (nLength < INT_MAX-1) ? (char*) VSIMalloc(nLength + 1) : NULL;
|
|
if( *ppszStr == NULL )
|
|
return FALSE;
|
|
if( nLength > 0 && !GDALPipeRead_nolength(p, nLength, *ppszStr) )
|
|
{
|
|
CPLFree(*ppszStr);
|
|
*ppszStr = NULL;
|
|
return FALSE;
|
|
}
|
|
(*ppszStr)[nLength] = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static int GDALPipeRead(GDALPipe* p, char*** ppapszStr)
|
|
{
|
|
int nStrCount;
|
|
if( !GDALPipeRead(p, &nStrCount) )
|
|
return FALSE;
|
|
if( nStrCount < 0 )
|
|
{
|
|
*ppapszStr = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
*ppapszStr = (char**) VSIMalloc2(sizeof(char*), (nStrCount + 1));
|
|
if( *ppapszStr == NULL )
|
|
return FALSE;
|
|
for(int i=0;i<nStrCount;i++)
|
|
{
|
|
if( !GDALPipeRead(p, (*ppapszStr) + i) )
|
|
{
|
|
CSLDestroy(*ppapszStr);
|
|
*ppapszStr = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
(*ppapszStr)[nStrCount] = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, int nItems, int** ppanInt)
|
|
{
|
|
int nSize;
|
|
*ppanInt = NULL;
|
|
if( !GDALPipeRead(p, &nSize) )
|
|
return FALSE;
|
|
if( nSize != nItems * (int)sizeof(int) )
|
|
return FALSE;
|
|
*ppanInt = (int*) VSIMalloc(nSize);
|
|
if( *ppanInt == NULL )
|
|
return FALSE;
|
|
if( !GDALPipeRead_nolength(p, nSize, *ppanInt) )
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, int nItems, GUIntBig** ppanInt)
|
|
{
|
|
int nSize;
|
|
*ppanInt = NULL;
|
|
if( !GDALPipeRead(p, &nSize) )
|
|
return FALSE;
|
|
if( nSize != nItems * (int)sizeof(GUIntBig) )
|
|
return FALSE;
|
|
*ppanInt = (GUIntBig*) VSIMalloc(nSize);
|
|
if( *ppanInt == NULL )
|
|
return FALSE;
|
|
if( !GDALPipeRead_nolength(p, nSize, *ppanInt) )
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, GDALColorTable** ppoColorTable)
|
|
{
|
|
int nPaletteInterp, nCount;
|
|
*ppoColorTable = NULL;
|
|
if( !GDALPipeRead(p, &nPaletteInterp) )
|
|
return FALSE;
|
|
GDALColorTable* poColorTable;
|
|
if( nPaletteInterp < 0 )
|
|
{
|
|
poColorTable = NULL;
|
|
}
|
|
else
|
|
{
|
|
if( !GDALPipeRead(p, &nCount) )
|
|
return FALSE;
|
|
poColorTable = new GDALColorTable((GDALPaletteInterp)nPaletteInterp);
|
|
for(int i=0; i<nCount; i++)
|
|
{
|
|
int c1, c2, c3, c4;
|
|
if( !GDALPipeRead(p, &c1) ||
|
|
!GDALPipeRead(p, &c2) ||
|
|
!GDALPipeRead(p, &c3) ||
|
|
!GDALPipeRead(p, &c4) )
|
|
{
|
|
delete poColorTable;
|
|
return FALSE;
|
|
}
|
|
GDALColorEntry eEntry;
|
|
eEntry.c1 = (short)c1;
|
|
eEntry.c2 = (short)c2;
|
|
eEntry.c3 = (short)c3;
|
|
eEntry.c4 = (short)c4;
|
|
poColorTable->SetColorEntry(i, &eEntry);
|
|
}
|
|
}
|
|
*ppoColorTable = poColorTable;
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, GDALRasterAttributeTable** ppoRAT)
|
|
{
|
|
*ppoRAT = NULL;
|
|
char* pszRAT = NULL;
|
|
if( !GDALPipeRead(p, &pszRAT))
|
|
return FALSE;
|
|
if( pszRAT == NULL )
|
|
return TRUE;
|
|
|
|
CPLXMLNode* poNode = CPLParseXMLString( pszRAT );
|
|
CPLFree(pszRAT);
|
|
if( poNode == NULL )
|
|
return FALSE;
|
|
|
|
*ppoRAT = new GDALDefaultRasterAttributeTable();
|
|
if( (*ppoRAT)->XMLInit(poNode, NULL) != CE_None )
|
|
{
|
|
CPLDestroyXMLNode(poNode);
|
|
delete *ppoRAT;
|
|
*ppoRAT = NULL;
|
|
return FALSE;
|
|
}
|
|
CPLDestroyXMLNode(poNode);
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, int* pnGCPCount, GDAL_GCP** ppasGCPs)
|
|
{
|
|
*pnGCPCount = 0;
|
|
*ppasGCPs = NULL;
|
|
int nGCPCount;
|
|
if( !GDALPipeRead(p, &nGCPCount) )
|
|
return FALSE;
|
|
GDAL_GCP* pasGCPs = (GDAL_GCP* )CPLCalloc(nGCPCount, sizeof(GDAL_GCP));
|
|
for(int i=0;i<nGCPCount;i++)
|
|
{
|
|
if( !GDALPipeRead(p, &pasGCPs[i].pszId) ||
|
|
!GDALPipeRead(p, &pasGCPs[i].pszInfo) ||
|
|
!GDALPipeRead(p, &pasGCPs[i].dfGCPPixel) ||
|
|
!GDALPipeRead(p, &pasGCPs[i].dfGCPLine) ||
|
|
!GDALPipeRead(p, &pasGCPs[i].dfGCPX) ||
|
|
!GDALPipeRead(p, &pasGCPs[i].dfGCPY) ||
|
|
!GDALPipeRead(p, &pasGCPs[i].dfGCPZ) )
|
|
{
|
|
GDALDeinitGCPs(i, pasGCPs);
|
|
CPLFree(pasGCPs);
|
|
return FALSE;
|
|
}
|
|
}
|
|
*pnGCPCount = nGCPCount;
|
|
*ppasGCPs = pasGCPs;
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeRead(GDALPipe* p, GDALClientDataset* poDS,
|
|
GDALRasterBand** ppoBand, GByte abyCaps[16])
|
|
{
|
|
int iSrvBand;
|
|
*ppoBand = NULL;
|
|
if( !GDALPipeRead(p, &iSrvBand) )
|
|
return FALSE;
|
|
if( iSrvBand < 0 )
|
|
return TRUE;
|
|
|
|
int iBand, nBandAccess, nXSize, nYSize, nDataType, nBlockXSize, nBlockYSize;
|
|
if( !GDALPipeRead(p, &iBand) ||
|
|
!GDALPipeRead(p, &nBandAccess) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nDataType) ||
|
|
!GDALPipeRead(p, &nBlockXSize) ||
|
|
!GDALPipeRead(p, &nBlockYSize) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
char* pszDescription = NULL;
|
|
if( !GDALPipeRead(p, &pszDescription) )
|
|
return FALSE;
|
|
|
|
GDALClientRasterBand* poBand = new GDALClientRasterBand(p, iSrvBand,
|
|
poDS, iBand, (GDALAccess)nBandAccess,
|
|
nXSize, nYSize,
|
|
(GDALDataType)nDataType,
|
|
nBlockXSize, nBlockYSize, abyCaps);
|
|
if( pszDescription != NULL )
|
|
poBand->GDALMajorObject::SetDescription(pszDescription);
|
|
CPLFree(pszDescription);
|
|
|
|
*ppoBand = poBand;
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALSkipUntilEndOfJunkMarker() */
|
|
/************************************************************************/
|
|
|
|
static int GDALSkipUntilEndOfJunkMarker(GDALPipe* p)
|
|
{
|
|
if(!p->bOK)
|
|
return FALSE;
|
|
GByte c;
|
|
size_t nIter = 0;
|
|
int nStep = 0;
|
|
CPLString osJunk;
|
|
int nMarkerSize = (int)sizeof(abyEndOfJunkMarker);
|
|
GByte abyBuffer[sizeof(abyEndOfJunkMarker)];
|
|
if( !GDALPipeRead_nolength(p, sizeof(abyBuffer), abyBuffer ) )
|
|
return FALSE;
|
|
if( memcmp(abyEndOfJunkMarker, abyBuffer, sizeof(abyBuffer)) == 0 )
|
|
return TRUE;
|
|
while(TRUE)
|
|
{
|
|
if( nIter < sizeof(abyBuffer) )
|
|
c = abyBuffer[nIter ++];
|
|
else if( !GDALPipeRead_nolength(p, 1, &c ) )
|
|
return FALSE;
|
|
|
|
if( c != 0 )
|
|
osJunk += c;
|
|
if( c == abyEndOfJunkMarker[0] ) nStep = 1;
|
|
else if( c == abyEndOfJunkMarker[nStep] )
|
|
{
|
|
nStep ++;
|
|
if( nStep == nMarkerSize )
|
|
{
|
|
osJunk.resize(osJunk.size() - nMarkerSize);
|
|
if( osJunk.size() )
|
|
CPLDebug("GDAL", "Got junk : %s", osJunk.c_str());
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
nStep = 0;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeWrite() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, int nInt)
|
|
{
|
|
return GDALPipeWrite(p, &nInt, 4);
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, GIntBig nInt)
|
|
{
|
|
return GDALPipeWrite(p, &nInt, 8);
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, double dfDouble)
|
|
{
|
|
return GDALPipeWrite(p, &dfDouble, 8);
|
|
}
|
|
|
|
static int GDALPipeWrite_nolength(GDALPipe* p, int nLength, const void* pabyData)
|
|
{
|
|
return GDALPipeWrite(p, pabyData, nLength);
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, int nLength, const void* pabyData)
|
|
{
|
|
if( !GDALPipeWrite(p, nLength) ||
|
|
!GDALPipeWrite_nolength(p, nLength, pabyData) )
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, const char* pszStr)
|
|
{
|
|
if( pszStr == NULL )
|
|
return GDALPipeWrite(p, 0);
|
|
return GDALPipeWrite(p, (int)strlen(pszStr) + 1, pszStr);
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, char** papszStr)
|
|
{
|
|
if( papszStr == NULL )
|
|
return GDALPipeWrite(p, -1);
|
|
|
|
int nCount = CSLCount(papszStr);
|
|
if( !GDALPipeWrite(p, nCount) )
|
|
return FALSE;
|
|
for(int i=0; i < nCount; i++)
|
|
{
|
|
if( !GDALPipeWrite(p, papszStr[i]) )
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p,
|
|
std::vector<GDALRasterBand*>& aBands,
|
|
GDALRasterBand* poBand)
|
|
{
|
|
if( poBand == NULL )
|
|
GDALPipeWrite(p, -1);
|
|
else
|
|
{
|
|
GDALPipeWrite(p, (int)aBands.size());
|
|
aBands.push_back(poBand);
|
|
GDALPipeWrite(p, poBand->GetBand());
|
|
GDALPipeWrite(p, poBand->GetAccess());
|
|
GDALPipeWrite(p, poBand->GetXSize());
|
|
GDALPipeWrite(p, poBand->GetYSize());
|
|
GDALPipeWrite(p, poBand->GetRasterDataType());
|
|
int nBlockXSize, nBlockYSize;
|
|
poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
|
|
GDALPipeWrite(p, nBlockXSize);
|
|
GDALPipeWrite(p, nBlockYSize);
|
|
GDALPipeWrite(p, poBand->GetDescription() );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, GDALColorTable* poColorTable)
|
|
{
|
|
if( poColorTable == NULL )
|
|
{
|
|
if( !GDALPipeWrite(p, -1) )
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
int nCount = poColorTable->GetColorEntryCount();
|
|
if( !GDALPipeWrite(p, poColorTable->GetPaletteInterpretation()) ||
|
|
!GDALPipeWrite(p, nCount) )
|
|
return FALSE;
|
|
|
|
for(int i=0; i < nCount; i++)
|
|
{
|
|
const GDALColorEntry* poColorEntry = poColorTable->GetColorEntry(i);
|
|
if( !GDALPipeWrite(p, poColorEntry->c1) ||
|
|
!GDALPipeWrite(p, poColorEntry->c2) ||
|
|
!GDALPipeWrite(p, poColorEntry->c3) ||
|
|
!GDALPipeWrite(p, poColorEntry->c4) )
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, const GDALRasterAttributeTable* poRAT)
|
|
{
|
|
int bRet;
|
|
if( poRAT == NULL )
|
|
bRet = GDALPipeWrite(p, (const char*)NULL);
|
|
else
|
|
{
|
|
CPLXMLNode* poNode = poRAT->Serialize();
|
|
if( poNode != NULL )
|
|
{
|
|
char* pszRAT = CPLSerializeXMLTree(poNode);
|
|
bRet = GDALPipeWrite(p, pszRAT);
|
|
CPLFree(pszRAT);
|
|
CPLDestroyXMLNode(poNode);
|
|
}
|
|
else
|
|
bRet = GDALPipeWrite(p, (const char*)NULL);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
static int GDALPipeWrite(GDALPipe* p, int nGCPCount, const GDAL_GCP* pasGCPs)
|
|
{
|
|
if( !GDALPipeWrite(p, nGCPCount ) )
|
|
return FALSE;
|
|
for(int i=0;i<nGCPCount;i++)
|
|
{
|
|
if( !GDALPipeWrite(p, pasGCPs[i].pszId) ||
|
|
!GDALPipeWrite(p, pasGCPs[i].pszInfo) ||
|
|
!GDALPipeWrite(p, pasGCPs[i].dfGCPPixel) ||
|
|
!GDALPipeWrite(p, pasGCPs[i].dfGCPLine) ||
|
|
!GDALPipeWrite(p, pasGCPs[i].dfGCPX) ||
|
|
!GDALPipeWrite(p, pasGCPs[i].dfGCPY) ||
|
|
!GDALPipeWrite(p, pasGCPs[i].dfGCPZ) )
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALPipeWriteConfigOption() */
|
|
/************************************************************************/
|
|
|
|
static int GDALPipeWriteConfigOption(GDALPipe* p, const char* pszKey,
|
|
int bWriteIfNonNull = TRUE)
|
|
{
|
|
const char* pszVal = CPLGetConfigOption(pszKey, NULL);
|
|
if( pszVal == NULL && !bWriteIfNonNull )
|
|
return TRUE;
|
|
return GDALPipeWrite(p, INSTR_SetConfigOption) &&
|
|
GDALPipeWrite(p, pszKey) &&
|
|
GDALPipeWrite(p, pszVal);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALEmitEndOfJunkMarker() */
|
|
/************************************************************************/
|
|
|
|
/* When receiving an instruction : */
|
|
/* - read all input arguments */
|
|
/* - do the call to the dataset or the band */
|
|
/* - as the previous call may potentially emit */
|
|
/* unwanted content on the stdout, we emit */
|
|
/* a special marker that the receiver will */
|
|
/* wait until interpreting the rest of the */
|
|
/* output arguments */
|
|
/* - emit output arguments */
|
|
static int GDALEmitEndOfJunkMarker(GDALPipe* p)
|
|
{
|
|
return GDALPipeWrite_nolength(p, sizeof(abyEndOfJunkMarker),
|
|
abyEndOfJunkMarker) ==
|
|
(int)sizeof(abyEndOfJunkMarker);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALConsumeErrors() */
|
|
/************************************************************************/
|
|
|
|
static void GDALConsumeErrors(GDALPipe* p)
|
|
{
|
|
int nErrors;
|
|
if( !GDALPipeRead(p, &nErrors) )
|
|
return;
|
|
for(int i=0;i<nErrors;i++)
|
|
{
|
|
int eErr;
|
|
int nErrNo;
|
|
char *pszErrorMsg = NULL;
|
|
if( !GDALPipeRead(p, &eErr) ||
|
|
!GDALPipeRead(p, &nErrNo) ||
|
|
!GDALPipeRead(p, &pszErrorMsg) )
|
|
return;
|
|
CPLError((CPLErr)eErr, nErrNo, "%s", pszErrorMsg ? pszErrorMsg : "unknown");
|
|
CPLFree(pszErrorMsg);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALEmitReset() */
|
|
/************************************************************************/
|
|
|
|
static int GDALEmitReset(GDALPipe* p)
|
|
{
|
|
int bOK;
|
|
if( !GDALPipeWrite(p, INSTR_Reset) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p) ||
|
|
!GDALPipeRead(p, &bOK) )
|
|
return FALSE;
|
|
GDALConsumeErrors(p);
|
|
return bOK;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALEmitEXIT() */
|
|
/************************************************************************/
|
|
|
|
static int GDALEmitEXIT(GDALPipe* p, InstrEnum instr = INSTR_EXIT )
|
|
{
|
|
int bOK;
|
|
if( !GDALPipeWrite(p, instr) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p) ||
|
|
!GDALPipeRead(p, &bOK) )
|
|
return FALSE;
|
|
return bOK;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALServerSpawnAsyncFinish() */
|
|
/************************************************************************/
|
|
|
|
static int GDALServerSpawnAsyncFinish(GDALServerSpawnedProcess* ssp)
|
|
{
|
|
if( bRecycleChild && ssp->p->bOK )
|
|
{
|
|
/* Store the descriptor in a free slot if available for a */
|
|
/* later reuse */
|
|
CPLMutexHolderD(GDALGetphDMMutex());
|
|
for(int i = 0; i < nMaxRecycled; i ++)
|
|
{
|
|
if( aspRecycled[i] == NULL )
|
|
{
|
|
if( !GDALEmitReset(ssp->p) )
|
|
break;
|
|
|
|
aspRecycled[i] = ssp;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ssp->p->bOK)
|
|
{
|
|
GDALEmitEXIT(ssp->p);
|
|
}
|
|
|
|
CPLDebug("GDAL", "Destroy spawned process %p", ssp);
|
|
GDALPipeFree(ssp->p);
|
|
int nRet = ssp->sp ? CPLSpawnAsyncFinish(ssp->sp, TRUE, TRUE) : 0;
|
|
CPLFree(ssp);
|
|
return nRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALCheckServerVersion() */
|
|
/************************************************************************/
|
|
|
|
static int GDALCheckServerVersion(GDALPipe* p)
|
|
{
|
|
GDALPipeWrite(p, INSTR_GetGDALVersion);
|
|
char bIsLSB = CPL_IS_LSB;
|
|
GDALPipeWrite_nolength(p, 1, &bIsLSB);
|
|
GDALPipeWrite(p, GDAL_RELEASE_NAME);
|
|
GDALPipeWrite(p, GDAL_VERSION_MAJOR);
|
|
GDALPipeWrite(p, GDAL_VERSION_MINOR);
|
|
GDALPipeWrite(p, GDAL_CLIENT_SERVER_PROTOCOL_MAJOR);
|
|
GDALPipeWrite(p, GDAL_CLIENT_SERVER_PROTOCOL_MINOR);
|
|
GDALPipeWrite(p, 0); /* extra bytes */
|
|
|
|
char* pszVersion = NULL;
|
|
int nMajor, nMinor, nProtocolMajor, nProtocolMinor, nExtraBytes;
|
|
if( !GDALPipeRead(p, &pszVersion) ||
|
|
!GDALPipeRead(p, &nMajor) ||
|
|
!GDALPipeRead(p, &nMinor) ||
|
|
!GDALPipeRead(p, &nProtocolMajor) ||
|
|
!GDALPipeRead(p, &nProtocolMinor) ||
|
|
!GDALPipeRead(p, &nExtraBytes) )
|
|
{
|
|
CPLFree(pszVersion);
|
|
return FALSE;
|
|
}
|
|
|
|
if( nExtraBytes > 0 )
|
|
{
|
|
void* pTemp = VSIMalloc(nExtraBytes);
|
|
if( !pTemp )
|
|
{
|
|
CPLFree(pszVersion);
|
|
return FALSE;
|
|
}
|
|
if( !GDALPipeRead_nolength(p, nExtraBytes, pTemp) )
|
|
{
|
|
CPLFree(pszVersion);
|
|
CPLFree(pTemp);
|
|
return FALSE;
|
|
}
|
|
CPLFree(pTemp);
|
|
}
|
|
|
|
CPLDebug("GDAL",
|
|
"Server version : %s (%d.%d), "
|
|
"Server protocol version = %d.%d",
|
|
pszVersion,
|
|
nMajor, nMinor,
|
|
nProtocolMajor, nProtocolMinor);
|
|
CPLDebug("GDAL",
|
|
"Client version : %s (%d.%d), "
|
|
"Client protocol version = %d.%d",
|
|
GDAL_RELEASE_NAME, GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR,
|
|
GDAL_CLIENT_SERVER_PROTOCOL_MAJOR,
|
|
GDAL_CLIENT_SERVER_PROTOCOL_MINOR);
|
|
if( nProtocolMajor != GDAL_CLIENT_SERVER_PROTOCOL_MAJOR )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"GDAL server (GDAL version=%s, protocol version=%d.%d) is "
|
|
"incompatible with GDAL client (GDAL version=%s, protocol version=%d.%d)",
|
|
pszVersion,
|
|
nProtocolMajor, nProtocolMinor,
|
|
GDAL_RELEASE_NAME,
|
|
GDAL_CLIENT_SERVER_PROTOCOL_MAJOR,
|
|
GDAL_CLIENT_SERVER_PROTOCOL_MINOR);
|
|
CPLFree(pszVersion);
|
|
return FALSE;
|
|
}
|
|
else if( nProtocolMinor != GDAL_CLIENT_SERVER_PROTOCOL_MINOR )
|
|
{
|
|
CPLDebug("GDAL", "Note: client/server protocol versions differ by minor number.");
|
|
}
|
|
CPLFree(pszVersion);
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALServerLoopForked() */
|
|
/************************************************************************/
|
|
|
|
#ifndef WIN32
|
|
void CPLReinitAllMutex();
|
|
|
|
static int GDALServerLoopForked(CPL_FILE_HANDLE fin, CPL_FILE_HANDLE fout)
|
|
{
|
|
/* Do not try to close datasets at process closing */
|
|
GDALNullifyOpenDatasetsList();
|
|
/* Nullify the existing mutex to avoid issues with locked mutex by */
|
|
/* parent's process threads */
|
|
GDALNullifyProxyPoolSingleton();
|
|
#ifdef CPL_MULTIPROC_PTHREAD
|
|
CPLReinitAllMutex();
|
|
#endif
|
|
|
|
memset(aspRecycled, 0, sizeof(aspRecycled));
|
|
|
|
return GDALServerLoop(fin, fout);
|
|
}
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* GDALServerSpawnAsync() */
|
|
/************************************************************************/
|
|
|
|
static GDALServerSpawnedProcess* GDALServerSpawnAsync()
|
|
{
|
|
if( bRecycleChild )
|
|
{
|
|
/* Try to find an existing unused descriptor to reuse it */
|
|
CPLMutexHolderD(GDALGetphDMMutex());
|
|
for(int i = 0; i < nMaxRecycled; i ++)
|
|
{
|
|
if( aspRecycled[i] != NULL )
|
|
{
|
|
GDALServerSpawnedProcess* ssp = aspRecycled[i];
|
|
aspRecycled[i] = NULL;
|
|
return ssp;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef WIN32
|
|
const char* pszSpawnServer = CPLGetConfigOption("GDAL_API_PROXY_SERVER", "gdalserver");
|
|
#else
|
|
const char* pszSpawnServer = CPLGetConfigOption("GDAL_API_PROXY_SERVER", "NO");
|
|
#endif
|
|
|
|
const char* pszColon = strchr(pszSpawnServer, ':');
|
|
if( pszColon != NULL &&
|
|
pszColon != pszSpawnServer + 1 /* do not confuse with c:/some_path/gdalserver.exe */ )
|
|
{
|
|
CPLString osHost(pszSpawnServer);
|
|
osHost.resize(pszColon - pszSpawnServer);
|
|
CPL_SOCKET nConnSocket = INVALID_SOCKET;
|
|
int nRet;
|
|
|
|
#ifdef WIN32
|
|
WSADATA wsaData;
|
|
|
|
nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
if (nRet != NO_ERROR)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"WSAStartup() failed with error: %d\n", nRet);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_GETADDRINFO
|
|
struct addrinfo sHints;
|
|
struct addrinfo* psResults = NULL, *psResultsIter;
|
|
memset(&sHints, 0, sizeof(struct addrinfo));
|
|
sHints.ai_family = AF_UNSPEC;
|
|
sHints.ai_socktype = SOCK_STREAM;
|
|
sHints.ai_flags = 0;
|
|
sHints.ai_protocol = IPPROTO_TCP;
|
|
|
|
nRet = getaddrinfo(osHost, pszColon + 1, &sHints, &psResults);
|
|
if (nRet)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"getaddrinfo(): %s", gai_strerror(nRet));
|
|
WSACleanup();
|
|
return NULL;
|
|
}
|
|
|
|
for( psResultsIter = psResults;
|
|
psResultsIter != NULL;
|
|
psResultsIter = psResultsIter->ai_next)
|
|
{
|
|
nConnSocket = socket(psResultsIter->ai_family,
|
|
psResultsIter->ai_socktype,
|
|
psResultsIter->ai_protocol);
|
|
if (nConnSocket == INVALID_SOCKET)
|
|
continue;
|
|
|
|
if (connect(nConnSocket, psResultsIter->ai_addr,
|
|
psResultsIter->ai_addrlen) != SOCKET_ERROR)
|
|
break;
|
|
|
|
closesocket(nConnSocket);
|
|
}
|
|
|
|
freeaddrinfo(psResults);
|
|
|
|
if (psResultsIter == NULL)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Could not connect");
|
|
WSACleanup();
|
|
return NULL;
|
|
}
|
|
#else
|
|
struct sockaddr_in sockAddrIn;
|
|
int nPort = atoi(pszColon + 1);
|
|
sockAddrIn.sin_family = AF_INET;
|
|
sockAddrIn.sin_addr.s_addr = inet_addr(osHost);
|
|
if (sockAddrIn.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
struct hostent *hp;
|
|
hp = gethostbyname(osHost);
|
|
if (hp == NULL)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Unknown host : %s", osHost.c_str());
|
|
WSACleanup();
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
sockAddrIn.sin_family = hp->h_addrtype;
|
|
memcpy(&(sockAddrIn.sin_addr.s_addr), hp->h_addr, hp->h_length);
|
|
}
|
|
}
|
|
sockAddrIn.sin_port = htons(nPort);
|
|
|
|
nConnSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (nConnSocket == INVALID_SOCKET)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"socket() failed with error: %d", WSAGetLastError());
|
|
WSACleanup();
|
|
return NULL;
|
|
}
|
|
|
|
if (connect(nConnSocket, (const SOCKADDR *)&sockAddrIn, sizeof (sockAddrIn)) == SOCKET_ERROR )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"connect() function failed with error: %d", WSAGetLastError());
|
|
closesocket(nConnSocket);
|
|
WSACleanup();
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
GDALServerSpawnedProcess* ssp =
|
|
(GDALServerSpawnedProcess*)CPLMalloc(sizeof(GDALServerSpawnedProcess));
|
|
ssp->sp = NULL;
|
|
ssp->p = GDALPipeBuild(nConnSocket);
|
|
|
|
CPLDebug("GDAL", "Create spawned process %p", ssp);
|
|
if( !GDALCheckServerVersion(ssp->p) )
|
|
{
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return NULL;
|
|
}
|
|
return ssp;
|
|
}
|
|
|
|
#ifndef WIN32
|
|
VSIStatBuf sStat;
|
|
if( VSIStat(pszSpawnServer, &sStat) == 0 && sStat.st_size == 0 )
|
|
{
|
|
int nConnSocket = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (nConnSocket >= 0)
|
|
{
|
|
struct sockaddr_un sockAddrUnix;
|
|
sockAddrUnix.sun_family = AF_UNIX;
|
|
CPLStrlcpy(sockAddrUnix.sun_path, pszSpawnServer, sizeof(sockAddrUnix.sun_path));
|
|
|
|
if (connect(nConnSocket, (const SOCKADDR *)&sockAddrUnix, sizeof (sockAddrUnix)) >= 0 )
|
|
{
|
|
GDALServerSpawnedProcess* ssp =
|
|
(GDALServerSpawnedProcess*)CPLMalloc(sizeof(GDALServerSpawnedProcess));
|
|
ssp->sp = NULL;
|
|
ssp->p = GDALPipeBuild(nConnSocket);
|
|
|
|
CPLDebug("GDAL", "Create spawned process %p", ssp);
|
|
if( !GDALCheckServerVersion(ssp->p) )
|
|
{
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return NULL;
|
|
}
|
|
return ssp;
|
|
}
|
|
else
|
|
closesocket(nConnSocket);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if( EQUAL(pszSpawnServer, "YES") || EQUAL(pszSpawnServer, "ON") ||
|
|
EQUAL(pszSpawnServer, "TRUE") || EQUAL(pszSpawnServer, "1") )
|
|
pszSpawnServer = "gdalserver";
|
|
#ifdef WIN32
|
|
const char* apszGDALServer[] = { pszSpawnServer, "-stdinout", NULL };
|
|
#else
|
|
const char* apszGDALServer[] = { pszSpawnServer, "-pipe_in", "{pipe_in}", "-pipe_out", "{pipe_out}", NULL };
|
|
if( strstr(pszSpawnServer, "gdalserver") == NULL )
|
|
apszGDALServer[1] = NULL;
|
|
#endif
|
|
int bCheckVersions = TRUE;
|
|
|
|
CPLSpawnedProcess* sp;
|
|
#ifndef WIN32
|
|
if( EQUAL(pszSpawnServer, "NO") || EQUAL(pszSpawnServer, "OFF") ||
|
|
EQUAL(pszSpawnServer, "FALSE") || EQUAL(pszSpawnServer, "0") )
|
|
{
|
|
sp = CPLSpawnAsync(GDALServerLoopForked, NULL, TRUE, TRUE, FALSE, NULL);
|
|
bCheckVersions = FALSE;
|
|
}
|
|
else
|
|
#endif
|
|
sp = CPLSpawnAsync(NULL, apszGDALServer, TRUE, TRUE, FALSE, NULL);
|
|
|
|
if( sp == NULL )
|
|
return NULL;
|
|
|
|
GDALServerSpawnedProcess* ssp =
|
|
(GDALServerSpawnedProcess*)CPLMalloc(sizeof(GDALServerSpawnedProcess));
|
|
ssp->sp = sp;
|
|
ssp->p = GDALPipeBuild(sp);
|
|
|
|
CPLDebug("GDAL", "Create spawned process %p", ssp);
|
|
if( bCheckVersions && !GDALCheckServerVersion(ssp->p) )
|
|
{
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return NULL;
|
|
}
|
|
return ssp;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CPLErrOnlyRet() */
|
|
/************************************************************************/
|
|
|
|
static CPLErr CPLErrOnlyRet(GDALPipe* p)
|
|
{
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* RunErrorHandler() */
|
|
/************************************************************************/
|
|
|
|
class GDALServerErrorDesc
|
|
{
|
|
public:
|
|
GDALServerErrorDesc() {}
|
|
|
|
CPLErr eErr;
|
|
int nErrNo;
|
|
CPLString osErrorMsg;
|
|
};
|
|
|
|
static void CPL_STDCALL RunErrorHandler(CPLErr eErr, int nErrNo,
|
|
const char* pszErrorMsg)
|
|
{
|
|
GDALServerErrorDesc oDesc;
|
|
oDesc.eErr = eErr;
|
|
oDesc.nErrNo = nErrNo;
|
|
oDesc.osErrorMsg = pszErrorMsg;
|
|
std::vector<GDALServerErrorDesc>* paoErrors =
|
|
(std::vector<GDALServerErrorDesc>*) CPLGetErrorHandlerUserData();
|
|
if( paoErrors )
|
|
paoErrors->push_back(oDesc);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* RunAsyncProgress() */
|
|
/************************************************************************/
|
|
|
|
static int CPL_STDCALL RunAsyncProgress(double dfComplete,
|
|
const char *pszMessage,
|
|
void *pProgressArg)
|
|
{
|
|
/* We don't send the progress right now, since some drivers like ECW */
|
|
/* call the progress callback from an helper thread, while calling methods */
|
|
/* on the source dataset. So we could end up sending mixed content on the pipe */
|
|
/* to the client. The best is to transmit the progress in a regularly called method */
|
|
/* of the dataset, such as IReadBlock() / IRasterIO() */
|
|
GDALServerAsyncProgress* asyncp = (GDALServerAsyncProgress*)pProgressArg;
|
|
CPLMutexHolderD(&(asyncp->hMutex));
|
|
asyncp->bUpdated = TRUE;
|
|
asyncp->dfComplete = dfComplete;
|
|
CPLFree(asyncp->pszProgressMsg);
|
|
asyncp->pszProgressMsg = (pszMessage) ? CPLStrdup(pszMessage) : NULL;
|
|
return asyncp->bRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* RunSyncProgress() */
|
|
/************************************************************************/
|
|
|
|
static int CPL_STDCALL RunSyncProgress(double dfComplete,
|
|
const char *pszMessage,
|
|
void *pProgressArg)
|
|
{
|
|
GDALPipe* p = (GDALPipe*)pProgressArg;
|
|
if( !GDALPipeWrite(p, INSTR_Progress) ||
|
|
!GDALPipeWrite(p, dfComplete) ||
|
|
!GDALPipeWrite(p, pszMessage) )
|
|
return FALSE;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return FALSE;
|
|
int bRet = FALSE;
|
|
if( !GDALPipeRead(p, &bRet) )
|
|
return FALSE;
|
|
GDALConsumeErrors(p);
|
|
return bRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALServerLoop() */
|
|
/************************************************************************/
|
|
|
|
static int GDALServerLoop(GDALPipe* p,
|
|
GDALDataset* poSrcDS,
|
|
GDALProgressFunc pfnProgress, void* pProgressData)
|
|
{
|
|
GDALDataset* poDS = NULL;
|
|
std::vector<GDALRasterBand*> aBands;
|
|
std::vector<GDALServerErrorDesc> aoErrors;
|
|
int nRet = 1;
|
|
GDALServerAsyncProgress asyncp;
|
|
memset(&asyncp, 0, sizeof(asyncp));
|
|
asyncp.bRet = TRUE;
|
|
void* pBuffer = NULL;
|
|
int nBufferSize = 0;
|
|
|
|
const char* pszOldVal = CPLGetConfigOption("GDAL_API_PROXY", NULL);
|
|
char* pszOldValDup = (pszOldVal) ? CPLStrdup(pszOldVal) : NULL;
|
|
CPLSetThreadLocalConfigOption("GDAL_API_PROXY", "OFF");
|
|
|
|
if( poSrcDS == NULL )
|
|
CPLPushErrorHandlerEx(RunErrorHandler, &aoErrors);
|
|
|
|
// fprintf(stderr, "[%d] started\n", (int)getpid());
|
|
while(TRUE)
|
|
{
|
|
int instr;
|
|
if( !GDALPipeRead(p, &instr) )
|
|
{
|
|
// fprintf(stderr, "[%d] instr failed\n", (int)getpid());
|
|
break;
|
|
}
|
|
|
|
// fprintf(stderr, "[%d] %s\n", (int)getpid(), (instr >= 0 && instr < INSTR_END) ? apszInstr[instr] : "unknown");
|
|
|
|
GDALRasterBand* poBand = NULL;
|
|
|
|
if( instr == INSTR_EXIT )
|
|
{
|
|
if( poSrcDS == NULL && poDS != NULL )
|
|
{
|
|
GDALClose((GDALDatasetH)poDS);
|
|
poDS = NULL;
|
|
aBands.resize(0);
|
|
}
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, TRUE);
|
|
nRet = 0;
|
|
break;
|
|
}
|
|
else if( instr == INSTR_EXIT_FAIL )
|
|
{
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, TRUE);
|
|
break;
|
|
}
|
|
else if( instr == INSTR_GetGDALVersion ||
|
|
instr == 0x01000000 )
|
|
{
|
|
/* Do not change this protocol ! */
|
|
char bClientIsLSB;
|
|
char* pszClientVersion = NULL;
|
|
int nClientMajor, nClientMinor,
|
|
nClientProtocolMajor, nClientProtocolMinor,
|
|
nExtraBytes;
|
|
if( !GDALPipeRead_nolength(p, 1, &bClientIsLSB) )
|
|
break;
|
|
if( bClientIsLSB != CPL_IS_LSB )
|
|
{
|
|
fprintf(stderr, "Server does not understand client endianness.\n");
|
|
break;
|
|
}
|
|
|
|
if (!GDALPipeRead(p, &pszClientVersion) ||
|
|
!GDALPipeRead(p, &nClientMajor) ||
|
|
!GDALPipeRead(p, &nClientMinor) ||
|
|
!GDALPipeRead(p, &nClientProtocolMajor) ||
|
|
!GDALPipeRead(p, &nClientProtocolMinor) ||
|
|
!GDALPipeRead(p, &nExtraBytes) )
|
|
{
|
|
CPLFree(pszClientVersion);
|
|
break;
|
|
}
|
|
|
|
if( nExtraBytes > 0 )
|
|
{
|
|
void* pTemp = VSIMalloc(nExtraBytes);
|
|
if( !pTemp )
|
|
{
|
|
CPLFree(pszClientVersion);
|
|
break;
|
|
}
|
|
if( !GDALPipeRead_nolength(p, nExtraBytes, pTemp) )
|
|
{
|
|
CPLFree(pszClientVersion);
|
|
CPLFree(pTemp);
|
|
break;
|
|
}
|
|
CPLFree(pTemp);
|
|
}
|
|
|
|
CPLFree(pszClientVersion);
|
|
|
|
GDALPipeWrite(p, GDAL_RELEASE_NAME);
|
|
GDALPipeWrite(p, GDAL_VERSION_MAJOR);
|
|
GDALPipeWrite(p, GDAL_VERSION_MINOR);
|
|
GDALPipeWrite(p, GDAL_CLIENT_SERVER_PROTOCOL_MAJOR);
|
|
GDALPipeWrite(p, GDAL_CLIENT_SERVER_PROTOCOL_MINOR);
|
|
GDALPipeWrite(p, 0); /* extra bytes */
|
|
continue;
|
|
}
|
|
else if( instr == INSTR_SetConfigOption )
|
|
{
|
|
char *pszKey = NULL, *pszValue = NULL;
|
|
if( !GDALPipeRead(p, &pszKey) ||
|
|
!GDALPipeRead(p, &pszValue) )
|
|
{
|
|
CPLFree(pszKey);
|
|
break;
|
|
}
|
|
CPLSetConfigOption(pszKey, pszValue);
|
|
CPLFree(pszKey);
|
|
CPLFree(pszValue);
|
|
continue;
|
|
}
|
|
else if( instr == INSTR_Progress )
|
|
{
|
|
double dfProgress;
|
|
char* pszProgressMsg = NULL;
|
|
if( !GDALPipeRead(p, &dfProgress) ||
|
|
!GDALPipeRead(p, &pszProgressMsg) )
|
|
break;
|
|
int nRet = pfnProgress(dfProgress, pszProgressMsg, pProgressData);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, nRet);
|
|
CPLFree(pszProgressMsg);
|
|
}
|
|
else if( instr == INSTR_Reset )
|
|
{
|
|
if( poSrcDS == NULL && poDS != NULL )
|
|
{
|
|
GDALClose((GDALDatasetH)poDS);
|
|
poDS = NULL;
|
|
MyChdirRootDirectory();
|
|
aBands.resize(0);
|
|
}
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, TRUE);
|
|
}
|
|
else if( instr == INSTR_Open )
|
|
{
|
|
int nAccess;
|
|
char* pszFilename = NULL;
|
|
char* pszCWD = NULL;
|
|
if( !GDALPipeRead(p, &nAccess) ||
|
|
!GDALPipeRead(p, &pszFilename) ||
|
|
!GDALPipeRead(p, &pszCWD) )
|
|
{
|
|
CPLFree(pszFilename);
|
|
CPLFree(pszCWD);
|
|
break;
|
|
}
|
|
if( pszCWD != NULL )
|
|
{
|
|
MyChdir(pszCWD);
|
|
CPLFree(pszCWD);
|
|
}
|
|
if( poSrcDS != NULL )
|
|
poDS = poSrcDS;
|
|
else if( poDS == NULL && pszFilename != NULL )
|
|
poDS = (GDALDataset*) GDALOpen(pszFilename, (GDALAccess)nAccess);
|
|
CPLFree(pszFilename);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, poDS != NULL);
|
|
if( poDS != NULL )
|
|
{
|
|
CPLAssert(INSTR_END < 128);
|
|
GByte abyCaps[16]; /* 16 * 8 = 128 */
|
|
memset(abyCaps, 0, sizeof(abyCaps));
|
|
/* We implement all known instructions (except marker ones) */
|
|
for(int c = 1; c < INSTR_END; c++)
|
|
{
|
|
if( c != INSTR_Band_First && c != INSTR_Band_End )
|
|
abyCaps[c / 8] |= (1 << (c % 8));
|
|
}
|
|
GDALPipeWrite(p, sizeof(abyCaps), abyCaps);
|
|
GDALPipeWrite(p, poDS->GetDescription() );
|
|
GDALDriver* poDriver = poDS->GetDriver();
|
|
if( poDriver != NULL )
|
|
{
|
|
GDALPipeWrite(p, poDriver->GetDescription() );
|
|
char** papszItems = poDriver->GetMetadata();
|
|
for(int i = 0; papszItems[i] != NULL; i++ )
|
|
{
|
|
char* pszKey = NULL;
|
|
const char* pszVal = CPLParseNameValue(papszItems[i], &pszKey );
|
|
if( pszKey != NULL )
|
|
{
|
|
GDALPipeWrite(p, pszKey );
|
|
GDALPipeWrite(p, pszVal );
|
|
CPLFree(pszKey);
|
|
}
|
|
}
|
|
GDALPipeWrite(p, (const char*)NULL);
|
|
}
|
|
else
|
|
GDALPipeWrite(p, (const char*)NULL);
|
|
|
|
GDALPipeWrite(p, poDS->GetRasterXSize());
|
|
GDALPipeWrite(p, poDS->GetRasterYSize());
|
|
int nBands = poDS->GetRasterCount();
|
|
GDALPipeWrite(p, nBands);
|
|
int i;
|
|
int bAllSame = TRUE;
|
|
GDALRasterBand* poFirstBand = NULL;
|
|
int nFBBlockXSize = 0, nFBBlockYSize = 0;
|
|
|
|
/* Check if all bands are identical */
|
|
for(i=0;i<nBands;i++)
|
|
{
|
|
GDALRasterBand* poBand = poDS->GetRasterBand(i+1);
|
|
if( strlen(poBand->GetDescription()) > 0 )
|
|
{
|
|
bAllSame = FALSE;
|
|
break;
|
|
}
|
|
if( i == 0 )
|
|
{
|
|
poFirstBand = poBand;
|
|
poBand->GetBlockSize(&nFBBlockXSize, &nFBBlockYSize);
|
|
}
|
|
else
|
|
{
|
|
int nBlockXSize, nBlockYSize;
|
|
poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
|
|
if( poBand->GetXSize() != poFirstBand->GetXSize() ||
|
|
poBand->GetYSize() != poFirstBand->GetYSize() ||
|
|
poBand->GetRasterDataType() != poFirstBand->GetRasterDataType() ||
|
|
nBlockXSize != nFBBlockXSize ||
|
|
nBlockYSize != nFBBlockYSize )
|
|
{
|
|
bAllSame = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Transmit bands */
|
|
GDALPipeWrite(p, bAllSame);
|
|
for(i=0;i<nBands;i++)
|
|
{
|
|
GDALRasterBand* poBand = poDS->GetRasterBand(i+1);
|
|
if( i > 0 && bAllSame )
|
|
aBands.push_back(poBand);
|
|
else
|
|
GDALPipeWrite(p, aBands, poBand);
|
|
}
|
|
}
|
|
}
|
|
else if( instr == INSTR_Identify )
|
|
{
|
|
char* pszFilename = NULL;
|
|
char* pszCWD = NULL;
|
|
if( !GDALPipeRead(p, &pszFilename) ||
|
|
pszFilename == NULL ||
|
|
!GDALPipeRead(p, &pszCWD) )
|
|
{
|
|
CPLFree(pszFilename);
|
|
CPLFree(pszCWD);
|
|
break;
|
|
}
|
|
|
|
if( pszCWD != NULL )
|
|
{
|
|
MyChdir(pszCWD);
|
|
CPLFree(pszCWD);
|
|
}
|
|
|
|
int bRet = GDALIdentifyDriver(pszFilename, NULL) != NULL;
|
|
CPLFree(pszFilename);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, bRet);
|
|
aoErrors.resize(0);
|
|
}
|
|
else if( instr == INSTR_Create )
|
|
{
|
|
char* pszFilename = NULL;
|
|
char* pszCWD = NULL;
|
|
int nXSize, nYSize, nBands, nDataType;
|
|
char** papszOptions = NULL;
|
|
GDALDriver* poDriver = NULL;
|
|
if( !GDALPipeRead(p, &pszFilename) ||
|
|
pszFilename == NULL ||
|
|
!GDALPipeRead(p, &pszCWD) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBands) ||
|
|
!GDALPipeRead(p, &nDataType) ||
|
|
!GDALPipeRead(p, &papszOptions) )
|
|
{
|
|
CPLFree(pszFilename);
|
|
CPLFree(pszCWD);
|
|
break;
|
|
}
|
|
|
|
if( pszCWD != NULL )
|
|
{
|
|
MyChdir(pszCWD);
|
|
CPLFree(pszCWD);
|
|
}
|
|
|
|
const char* pszDriver = CSLFetchNameValue(papszOptions, "SERVER_DRIVER");
|
|
CPLString osDriver;
|
|
if( pszDriver != NULL )
|
|
{
|
|
osDriver = pszDriver;
|
|
pszDriver = osDriver.c_str();
|
|
poDriver = (GDALDriver* )GDALGetDriverByName(pszDriver);
|
|
}
|
|
papszOptions = CSLSetNameValue(papszOptions, "SERVER_DRIVER", NULL);
|
|
if( poDriver != NULL )
|
|
{
|
|
poDS = poDriver->Create(pszFilename, nXSize, nYSize, nBands,
|
|
(GDALDataType)nDataType,
|
|
papszOptions);
|
|
}
|
|
else
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s",
|
|
(pszDriver) ? pszDriver : "(unknown)");
|
|
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, poDS != NULL);
|
|
CPLFree(pszFilename);
|
|
CSLDestroy(papszOptions);
|
|
}
|
|
else if( instr == INSTR_CreateCopy )
|
|
{
|
|
char* pszFilename = NULL;
|
|
char* pszSrcDescription = NULL;
|
|
char* pszCWD = NULL;
|
|
char** papszCreateOptions = NULL;
|
|
GDALDriver* poDriver = NULL;
|
|
int bStrict = FALSE;
|
|
|
|
if( !GDALPipeRead(p, &pszFilename) ||
|
|
pszFilename == NULL ||
|
|
!GDALPipeRead(p, &pszSrcDescription) ||
|
|
!GDALPipeRead(p, &pszCWD) ||
|
|
!GDALPipeRead(p, &bStrict) ||
|
|
!GDALPipeRead(p, &papszCreateOptions) )
|
|
{
|
|
CPLFree(pszFilename);
|
|
CPLFree(pszSrcDescription);
|
|
CPLFree(pszCWD);
|
|
break;
|
|
}
|
|
|
|
CPLFree(pszSrcDescription);
|
|
|
|
if( pszCWD != NULL )
|
|
{
|
|
MyChdir(pszCWD);
|
|
CPLFree(pszCWD);
|
|
}
|
|
|
|
const char* pszDriver = CSLFetchNameValue(papszCreateOptions, "SERVER_DRIVER");
|
|
CPLString osDriver;
|
|
if( pszDriver != NULL )
|
|
{
|
|
osDriver = pszDriver;
|
|
pszDriver = osDriver.c_str();
|
|
poDriver = (GDALDriver* )GDALGetDriverByName(pszDriver);
|
|
}
|
|
papszCreateOptions = CSLSetNameValue(papszCreateOptions, "SERVER_DRIVER", NULL);
|
|
GDALPipeWrite(p, poDriver != NULL);
|
|
if( poDriver != NULL )
|
|
{
|
|
GDALClientDataset* poSrcDS = new GDALClientDataset(p);
|
|
if( !poSrcDS->Init(NULL, GA_ReadOnly) )
|
|
{
|
|
delete poSrcDS;
|
|
CPLFree(pszFilename);
|
|
CSLDestroy(papszCreateOptions);
|
|
break;
|
|
}
|
|
poSrcDS->AttachAsyncProgress(&asyncp);
|
|
|
|
poDS = poDriver->CreateCopy(pszFilename, poSrcDS,
|
|
bStrict, papszCreateOptions,
|
|
RunAsyncProgress, &asyncp);
|
|
|
|
int bProgressRet = poSrcDS->ProcessAsyncProgress();
|
|
GDALClose((GDALDatasetH)poSrcDS);
|
|
|
|
if( !bProgressRet && poDS != NULL )
|
|
{
|
|
GDALClose((GDALDatasetH)poDS);
|
|
poDS = NULL;
|
|
}
|
|
|
|
if( !GDALEmitEXIT(p, (poDS != NULL) ? INSTR_EXIT : INSTR_EXIT_FAIL) )
|
|
break;
|
|
}
|
|
else
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s",
|
|
(pszDriver) ? pszDriver : "(unknown)");
|
|
|
|
CPLFree(pszFilename);
|
|
CSLDestroy(papszCreateOptions);
|
|
}
|
|
else if( instr == INSTR_QuietDelete )
|
|
{
|
|
char* pszFilename = NULL;
|
|
char* pszCWD = NULL;
|
|
|
|
if( !GDALPipeRead(p, &pszFilename) ||
|
|
pszFilename == NULL ||
|
|
!GDALPipeRead(p, &pszCWD) )
|
|
{
|
|
CPLFree(pszFilename);
|
|
CPLFree(pszCWD);
|
|
break;
|
|
}
|
|
|
|
if( pszCWD != NULL )
|
|
{
|
|
MyChdir(pszCWD);
|
|
CPLFree(pszCWD);
|
|
}
|
|
|
|
GDALDriver::QuietDelete(pszFilename);
|
|
|
|
GDALEmitEndOfJunkMarker(p);
|
|
CPLFree(pszFilename);
|
|
}
|
|
else if( instr == INSTR_AddBand )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nType;
|
|
char** papszOptions = NULL;
|
|
if( !GDALPipeRead(p, &nType) ||
|
|
!GDALPipeRead(p, &papszOptions) )
|
|
break;
|
|
CPLErr eErr = poDS->AddBand((GDALDataType)nType, papszOptions);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr == CE_None )
|
|
{
|
|
int nBandCount = poDS->GetRasterCount();
|
|
GDALPipeWrite(p, aBands, poDS->GetRasterBand(nBandCount));
|
|
}
|
|
CSLDestroy(papszOptions);
|
|
}
|
|
else if( instr == INSTR_GetGeoTransform )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
double adfGeoTransform[6];
|
|
CPLErr eErr = poDS->GetGeoTransform(adfGeoTransform);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr != CE_Failure )
|
|
{
|
|
GDALPipeWrite(p, 6 * sizeof(double), adfGeoTransform);
|
|
}
|
|
}
|
|
else if( instr == INSTR_SetGeoTransform )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
double adfGeoTransform[6];
|
|
if( !GDALPipeRead(p, 6 * sizeof(double), adfGeoTransform) )
|
|
break;
|
|
CPLErr eErr = poDS->SetGeoTransform(adfGeoTransform);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_GetProjectionRef )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
const char* pszVal = poDS->GetProjectionRef();
|
|
//GDALPipeWrite(p, strlen("some_junk\xDE"), "some_junk\xDE");
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, pszVal);
|
|
}
|
|
else if( instr == INSTR_SetProjection )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char* pszProjection = NULL;
|
|
if( !GDALPipeRead(p, &pszProjection) )
|
|
break;
|
|
CPLErr eErr = poDS->SetProjection(pszProjection);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(pszProjection);
|
|
}
|
|
else if( instr == INSTR_GetGCPCount )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nGCPCount = poDS->GetGCPCount();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, nGCPCount );
|
|
}
|
|
else if( instr == INSTR_GetGCPProjection )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
const char* pszVal = poDS->GetGCPProjection();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, pszVal);
|
|
}
|
|
else if( instr == INSTR_GetGCPs )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nGCPCount = poDS->GetGCPCount();
|
|
const GDAL_GCP* pasGCPs = poDS->GetGCPs();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, nGCPCount, pasGCPs);
|
|
}
|
|
else if( instr == INSTR_SetGCPs )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nGCPCount;
|
|
GDAL_GCP* pasGCPs = NULL;
|
|
if( !GDALPipeRead(p, &nGCPCount, &pasGCPs) )
|
|
break;
|
|
char* pszGCPProjection = NULL;
|
|
if( !GDALPipeRead(p, &pszGCPProjection) )
|
|
break;
|
|
CPLErr eErr = poDS->SetGCPs(nGCPCount, pasGCPs, pszGCPProjection);
|
|
GDALDeinitGCPs(nGCPCount, pasGCPs);
|
|
CPLFree(pasGCPs);
|
|
CPLFree(pszGCPProjection);
|
|
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr );
|
|
|
|
}
|
|
else if( instr == INSTR_GetFileList )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char** papszFileList = poDS->GetFileList();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, papszFileList);
|
|
CSLDestroy(papszFileList);
|
|
}
|
|
else if( instr == INSTR_FlushCache )
|
|
{
|
|
if( poDS )
|
|
poDS->FlushCache();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
}
|
|
/*else if( instr == INSTR_SetDescription )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char* pszDescription = NULL;
|
|
if( !GDALPipeRead(p, &pszDescription) )
|
|
break;
|
|
poDS->SetDescription(pszDescription);
|
|
CPLFree(pszDescription);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
}*/
|
|
else if( instr == INSTR_GetMetadata )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &pszDomain) )
|
|
break;
|
|
char** papszMD = poDS->GetMetadata(pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
CPLFree(pszDomain);
|
|
GDALPipeWrite(p, papszMD);
|
|
}
|
|
else if( instr == INSTR_GetMetadataItem )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char* pszName = NULL;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &pszName) ||
|
|
!GDALPipeRead(p, &pszDomain) )
|
|
{
|
|
CPLFree(pszName);
|
|
CPLFree(pszDomain);
|
|
break;
|
|
}
|
|
const char* pszVal = poDS->GetMetadataItem(pszName, pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, pszVal);
|
|
CPLFree(pszName);
|
|
CPLFree(pszDomain);
|
|
}
|
|
else if( instr == INSTR_SetMetadata )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char** papszMetadata = NULL;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &papszMetadata) ||
|
|
!GDALPipeRead(p, &pszDomain) )
|
|
{
|
|
CSLDestroy(papszMetadata);
|
|
CPLFree(pszDomain);
|
|
break;
|
|
}
|
|
CPLErr eErr = poDS->SetMetadata(papszMetadata, pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CSLDestroy(papszMetadata);
|
|
CPLFree(pszDomain);
|
|
}
|
|
else if( instr == INSTR_SetMetadataItem )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char* pszName = NULL;
|
|
char* pszValue = NULL;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &pszName) ||
|
|
!GDALPipeRead(p, &pszValue) ||
|
|
!GDALPipeRead(p, &pszDomain) )
|
|
{
|
|
CPLFree(pszName);
|
|
CPLFree(pszValue);
|
|
CPLFree(pszDomain);
|
|
break;
|
|
}
|
|
CPLErr eErr = poDS->SetMetadataItem(pszName, pszValue, pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(pszName);
|
|
CPLFree(pszValue);
|
|
CPLFree(pszDomain);
|
|
}
|
|
else if( instr == INSTR_IBuildOverviews )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
char* pszResampling = NULL;
|
|
int nOverviews;
|
|
int* panOverviewList = NULL;
|
|
int nListBands;
|
|
int* panBandList = NULL;
|
|
if( !GDALPipeRead(p, &pszResampling) ||
|
|
!GDALPipeRead(p, &nOverviews) ||
|
|
!GDALPipeRead(p, nOverviews, &panOverviewList) ||
|
|
!GDALPipeRead(p, &nListBands) ||
|
|
!GDALPipeRead(p, nListBands, &panBandList) )
|
|
{
|
|
CPLFree(pszResampling);
|
|
CPLFree(panOverviewList);
|
|
CPLFree(panBandList);
|
|
break;
|
|
}
|
|
|
|
CPLErr eErr = poDS->BuildOverviews(pszResampling,
|
|
nOverviews, panOverviewList,
|
|
nListBands, panBandList,
|
|
RunSyncProgress, p);
|
|
|
|
CPLFree(pszResampling);
|
|
CPLFree(panOverviewList);
|
|
CPLFree(panBandList);
|
|
|
|
if( !GDALEmitEXIT(p, (eErr != CE_Failure) ? INSTR_EXIT : INSTR_EXIT_FAIL) )
|
|
break;
|
|
}
|
|
else if( instr == INSTR_AdviseRead )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize;
|
|
int nDT;
|
|
int nBandCount;
|
|
int *panBandList = NULL;
|
|
char** papszOptions = NULL;
|
|
int nLength = 0;
|
|
if( !GDALPipeRead(p, &nXOff) ||
|
|
!GDALPipeRead(p, &nYOff) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBufXSize) ||
|
|
!GDALPipeRead(p, &nBufYSize) ||
|
|
!GDALPipeRead(p, &nDT) ||
|
|
!GDALPipeRead(p, &nBandCount) ||
|
|
!GDALPipeRead(p, &nLength) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* panBandList can be NULL, hence the following test */
|
|
/* to check if we have band numbers to actually read */
|
|
if( nLength != 0 )
|
|
{
|
|
if( nLength != (int)sizeof(int) * nBandCount )
|
|
{
|
|
break;
|
|
}
|
|
|
|
panBandList = (int*) VSIMalloc(nLength);
|
|
if( panBandList == NULL )
|
|
break;
|
|
|
|
if( !GDALPipeRead_nolength(p, nLength, (void*)panBandList) )
|
|
{
|
|
VSIFree(panBandList);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!GDALPipeRead(p, &papszOptions) )
|
|
{
|
|
CPLFree(panBandList);
|
|
CSLDestroy(papszOptions);
|
|
break;
|
|
}
|
|
|
|
CPLErr eErr = poDS->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
|
|
(GDALDataType)nDT,
|
|
nBandCount, panBandList,
|
|
papszOptions);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(panBandList);
|
|
CSLDestroy(papszOptions);
|
|
}
|
|
else if( instr == INSTR_IRasterIO_Read )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nXOff, nYOff, nXSize, nYSize;
|
|
int nBufXSize, nBufYSize;
|
|
GDALDataType eBufType;
|
|
int nBufType;
|
|
int nBandCount;
|
|
GSpacing nPixelSpace, nLineSpace, nBandSpace;
|
|
int* panBandMap = NULL;
|
|
if( !GDALPipeRead(p, &nXOff) ||
|
|
!GDALPipeRead(p, &nYOff) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBufXSize) ||
|
|
!GDALPipeRead(p, &nBufYSize) ||
|
|
!GDALPipeRead(p, &nBufType) ||
|
|
!GDALPipeRead(p, &nBandCount) ||
|
|
!GDALPipeRead(p, nBandCount, &panBandMap) ||
|
|
!GDALPipeRead(p, &nPixelSpace) ||
|
|
!GDALPipeRead(p, &nLineSpace) ||
|
|
!GDALPipeRead(p, &nBandSpace) )
|
|
{
|
|
CPLFree(panBandMap);
|
|
break;
|
|
}
|
|
/* Note: only combinations of nPixelSpace, nLineSpace and
|
|
nBandSpace that lead to compate band-interleaved or pixel-
|
|
interleaved buffers are valid. Other combinations will lead to segfault */
|
|
eBufType = (GDALDataType)nBufType;
|
|
int nSize = nBufXSize * nBufYSize * nBandCount *
|
|
(GDALGetDataTypeSize(eBufType) / 8);
|
|
if( nSize > nBufferSize )
|
|
{
|
|
nBufferSize = nSize;
|
|
pBuffer = CPLRealloc(pBuffer, nSize);
|
|
}
|
|
|
|
CPLErr eErr = poDS->RasterIO(GF_Read,
|
|
nXOff, nYOff, nXSize, nYSize,
|
|
pBuffer, nBufXSize, nBufYSize,
|
|
eBufType,
|
|
nBandCount, panBandMap,
|
|
nPixelSpace, nLineSpace, nBandSpace,
|
|
NULL);
|
|
CPLFree(panBandMap);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr != CE_Failure )
|
|
GDALPipeWrite(p, nSize, pBuffer);
|
|
}
|
|
else if( instr == INSTR_IRasterIO_Write )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nXOff, nYOff, nXSize, nYSize;
|
|
int nBufXSize, nBufYSize;
|
|
GDALDataType eBufType;
|
|
int nBufType;
|
|
int nBandCount;
|
|
GSpacing nPixelSpace, nLineSpace, nBandSpace;
|
|
int* panBandMap = NULL;
|
|
if( !GDALPipeRead(p, &nXOff) ||
|
|
!GDALPipeRead(p, &nYOff) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBufXSize) ||
|
|
!GDALPipeRead(p, &nBufYSize) ||
|
|
!GDALPipeRead(p, &nBufType) ||
|
|
!GDALPipeRead(p, &nBandCount) ||
|
|
!GDALPipeRead(p, nBandCount, &panBandMap) ||
|
|
!GDALPipeRead(p, &nPixelSpace) ||
|
|
!GDALPipeRead(p, &nLineSpace) ||
|
|
!GDALPipeRead(p, &nBandSpace) )
|
|
{
|
|
CPLFree(panBandMap);
|
|
break;
|
|
}
|
|
/* Note: only combinations of nPixelSpace, nLineSpace and
|
|
nBandSpace that lead to compate band-interleaved or pixel-
|
|
interleaved buffers are valid. Other combinations will lead to segfault */
|
|
eBufType = (GDALDataType)nBufType;
|
|
int nExpectedSize = nBufXSize * nBufYSize * nBandCount *
|
|
(GDALGetDataTypeSize(eBufType) / 8);
|
|
int nSize;
|
|
if( !GDALPipeRead(p, &nSize) )
|
|
break;
|
|
if( nSize != nExpectedSize )
|
|
break;
|
|
if( nSize > nBufferSize )
|
|
{
|
|
nBufferSize = nSize;
|
|
pBuffer = CPLRealloc(pBuffer, nSize);
|
|
}
|
|
if( !GDALPipeRead_nolength(p, nSize, pBuffer) )
|
|
break;
|
|
|
|
CPLErr eErr = poDS->RasterIO(GF_Write,
|
|
nXOff, nYOff, nXSize, nYSize,
|
|
pBuffer, nBufXSize, nBufYSize,
|
|
eBufType,
|
|
nBandCount, panBandMap,
|
|
nPixelSpace, nLineSpace, nBandSpace,
|
|
NULL);
|
|
CPLFree(panBandMap);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_CreateMaskBand )
|
|
{
|
|
if( poDS == NULL )
|
|
break;
|
|
int nFlags;
|
|
if( !GDALPipeRead(p, &nFlags) )
|
|
break;
|
|
CPLErr eErr = poDS->CreateMaskBand(nFlags);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr > INSTR_Band_First && instr < INSTR_Band_End )
|
|
{
|
|
int iBand;
|
|
if( !GDALPipeRead(p, &iBand) )
|
|
break;
|
|
if( iBand < 0 || iBand >= (int)aBands.size() )
|
|
break;
|
|
poBand = aBands[iBand];
|
|
}
|
|
else
|
|
break;
|
|
|
|
if( instr == INSTR_Band_FlushCache )
|
|
{
|
|
CPLErr eErr = poBand->FlushCache();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_GetCategoryNames )
|
|
{
|
|
char** papszCategoryNames = poBand->GetCategoryNames();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, papszCategoryNames);
|
|
}
|
|
else if( instr == INSTR_Band_SetCategoryNames )
|
|
{
|
|
char** papszCategoryNames = NULL;
|
|
if( !GDALPipeRead(p, &papszCategoryNames) )
|
|
break;
|
|
CPLErr eErr = poBand->SetCategoryNames(papszCategoryNames);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CSLDestroy(papszCategoryNames);
|
|
}
|
|
else if( instr == INSTR_Band_SetDescription )
|
|
{
|
|
char* pszDescription = NULL;
|
|
if( !GDALPipeRead(p, &pszDescription) )
|
|
break;
|
|
poBand->SetDescription(pszDescription);
|
|
CPLFree(pszDescription);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
}
|
|
else if( instr == INSTR_Band_GetMetadata )
|
|
{
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &pszDomain) )
|
|
break;
|
|
char** papszMD = poBand->GetMetadata(pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
CPLFree(pszDomain);
|
|
GDALPipeWrite(p, papszMD);
|
|
}
|
|
else if( instr == INSTR_Band_GetMetadataItem )
|
|
{
|
|
char* pszName = NULL;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &pszName) ||
|
|
!GDALPipeRead(p, &pszDomain) )
|
|
{
|
|
CPLFree(pszName);
|
|
CPLFree(pszDomain);
|
|
break;
|
|
}
|
|
const char* pszVal = poBand->GetMetadataItem(pszName, pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, pszVal);
|
|
CPLFree(pszName);
|
|
CPLFree(pszDomain);
|
|
}
|
|
else if( instr == INSTR_Band_SetMetadata )
|
|
{
|
|
char** papszMetadata = NULL;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &papszMetadata) ||
|
|
!GDALPipeRead(p, &pszDomain) )
|
|
{
|
|
CSLDestroy(papszMetadata);
|
|
CPLFree(pszDomain);
|
|
break;
|
|
}
|
|
CPLErr eErr = poBand->SetMetadata(papszMetadata, pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CSLDestroy(papszMetadata);
|
|
CPLFree(pszDomain);
|
|
}
|
|
else if( instr == INSTR_Band_SetMetadataItem )
|
|
{
|
|
char* pszName = NULL;
|
|
char* pszValue = NULL;
|
|
char* pszDomain = NULL;
|
|
if( !GDALPipeRead(p, &pszName) ||
|
|
!GDALPipeRead(p, &pszValue) ||
|
|
!GDALPipeRead(p, &pszDomain) )
|
|
{
|
|
CPLFree(pszName);
|
|
CPLFree(pszValue);
|
|
CPLFree(pszDomain);
|
|
break;
|
|
}
|
|
CPLErr eErr = poBand->SetMetadataItem(pszName, pszValue, pszDomain);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(pszName);
|
|
CPLFree(pszValue);
|
|
CPLFree(pszDomain);
|
|
}
|
|
else if( instr == INSTR_Band_GetColorInterpretation )
|
|
{
|
|
GDALColorInterp eInterp = poBand->GetColorInterpretation();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eInterp);
|
|
}
|
|
else if( instr == INSTR_Band_SetColorInterpretation )
|
|
{
|
|
int nVal;
|
|
if( !GDALPipeRead(p, &nVal ) )
|
|
break;
|
|
CPLErr eErr = poBand->SetColorInterpretation((GDALColorInterp)nVal);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_GetNoDataValue )
|
|
{
|
|
int bSuccess;
|
|
double dfVal = poBand->GetNoDataValue(&bSuccess);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, bSuccess);
|
|
GDALPipeWrite(p, dfVal);
|
|
}
|
|
else if( instr == INSTR_Band_GetMinimum )
|
|
{
|
|
int bSuccess;
|
|
double dfVal = poBand->GetMinimum(&bSuccess);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, bSuccess);
|
|
GDALPipeWrite(p, dfVal);
|
|
}
|
|
else if( instr == INSTR_Band_GetMaximum )
|
|
{
|
|
int bSuccess;
|
|
double dfVal = poBand->GetMaximum(&bSuccess);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, bSuccess);
|
|
GDALPipeWrite(p, dfVal);
|
|
}
|
|
else if( instr == INSTR_Band_GetScale )
|
|
{
|
|
int bSuccess;
|
|
double dfVal = poBand->GetScale(&bSuccess);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, bSuccess);
|
|
GDALPipeWrite(p, dfVal);
|
|
}
|
|
else if( instr == INSTR_Band_GetOffset )
|
|
{
|
|
int bSuccess;
|
|
double dfVal = poBand->GetOffset(&bSuccess);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, bSuccess);
|
|
GDALPipeWrite(p, dfVal);
|
|
}
|
|
else if( instr == INSTR_Band_SetNoDataValue )
|
|
{
|
|
double dfVal;
|
|
if( !GDALPipeRead(p, &dfVal ) )
|
|
break;
|
|
CPLErr eErr = poBand->SetNoDataValue(dfVal);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_SetOffset )
|
|
{
|
|
double dfVal;
|
|
if( !GDALPipeRead(p, &dfVal ) )
|
|
break;
|
|
CPLErr eErr = poBand->SetOffset(dfVal);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_SetScale )
|
|
{
|
|
double dfVal;
|
|
if( !GDALPipeRead(p, &dfVal ) )
|
|
break;
|
|
CPLErr eErr = poBand->SetScale(dfVal);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_IReadBlock )
|
|
{
|
|
int nBlockXOff, nBlockYOff;
|
|
if( !GDALPipeRead(p, &nBlockXOff) ||
|
|
!GDALPipeRead(p, &nBlockYOff) )
|
|
break;
|
|
int nBlockXSize, nBlockYSize;
|
|
poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
|
|
int nSize = nBlockXSize * nBlockYSize *
|
|
(GDALGetDataTypeSize(poBand->GetRasterDataType()) / 8);
|
|
if( nSize > nBufferSize )
|
|
{
|
|
nBufferSize = nSize;
|
|
pBuffer = CPLRealloc(pBuffer, nSize);
|
|
}
|
|
CPLErr eErr = poBand->ReadBlock(nBlockXOff, nBlockYOff, pBuffer);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
GDALPipeWrite(p, nSize, pBuffer);
|
|
}
|
|
else if( instr == INSTR_Band_IWriteBlock )
|
|
{
|
|
int nBlockXOff, nBlockYOff, nSize;
|
|
if( !GDALPipeRead(p, &nBlockXOff) ||
|
|
!GDALPipeRead(p, &nBlockYOff) ||
|
|
!GDALPipeRead(p, &nSize) )
|
|
break;
|
|
int nBlockXSize, nBlockYSize;
|
|
poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
|
|
int nExpectedSize = nBlockXSize * nBlockYSize *
|
|
(GDALGetDataTypeSize(poBand->GetRasterDataType()) / 8);
|
|
if( nExpectedSize != nSize )
|
|
break;
|
|
if( nSize > nBufferSize )
|
|
{
|
|
nBufferSize = nSize;
|
|
pBuffer = CPLRealloc(pBuffer, nSize);
|
|
}
|
|
if( !GDALPipeRead_nolength(p, nSize, pBuffer) )
|
|
break;
|
|
|
|
CPLErr eErr = poBand->WriteBlock(nBlockXOff, nBlockYOff, pBuffer);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_IRasterIO_Read )
|
|
{
|
|
int nXOff, nYOff, nXSize, nYSize;
|
|
int nBufXSize, nBufYSize;
|
|
GDALDataType eBufType;
|
|
int nBufType;
|
|
if( !GDALPipeRead(p, &nXOff) ||
|
|
!GDALPipeRead(p, &nYOff) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBufXSize) ||
|
|
!GDALPipeRead(p, &nBufYSize) ||
|
|
!GDALPipeRead(p, &nBufType) )
|
|
break;
|
|
eBufType = (GDALDataType)nBufType;
|
|
int nSize = nBufXSize * nBufYSize *
|
|
(GDALGetDataTypeSize(eBufType) / 8);
|
|
if( nSize > nBufferSize )
|
|
{
|
|
nBufferSize = nSize;
|
|
pBuffer = CPLRealloc(pBuffer, nSize);
|
|
}
|
|
|
|
CPLErr eErr = poBand->RasterIO(GF_Read,
|
|
nXOff, nYOff, nXSize, nYSize,
|
|
pBuffer, nBufXSize, nBufYSize,
|
|
eBufType, 0, 0, NULL);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
GDALPipeWrite(p, nSize, pBuffer);
|
|
}
|
|
else if( instr == INSTR_Band_IRasterIO_Write )
|
|
{
|
|
int nXOff, nYOff, nXSize, nYSize;
|
|
int nBufXSize, nBufYSize;
|
|
GDALDataType eBufType;
|
|
int nBufType;
|
|
if( !GDALPipeRead(p, &nXOff) ||
|
|
!GDALPipeRead(p, &nYOff) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBufXSize) ||
|
|
!GDALPipeRead(p, &nBufYSize) ||
|
|
!GDALPipeRead(p, &nBufType) )
|
|
break;
|
|
eBufType = (GDALDataType)nBufType;
|
|
int nExpectedSize = nBufXSize * nBufYSize *
|
|
(GDALGetDataTypeSize(eBufType) / 8);
|
|
int nSize;
|
|
if( !GDALPipeRead(p, &nSize) )
|
|
break;
|
|
if( nSize != nExpectedSize )
|
|
break;
|
|
if( nSize > nBufferSize )
|
|
{
|
|
nBufferSize = nSize;
|
|
pBuffer = CPLRealloc(pBuffer, nSize);
|
|
}
|
|
if( !GDALPipeRead_nolength(p, nSize, pBuffer) )
|
|
break;
|
|
|
|
CPLErr eErr = poBand->RasterIO(GF_Write,
|
|
nXOff, nYOff, nXSize, nYSize,
|
|
pBuffer, nBufXSize, nBufYSize,
|
|
eBufType, 0, 0, NULL);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_GetStatistics )
|
|
{
|
|
int bApproxOK, bForce;
|
|
if( !GDALPipeRead(p, &bApproxOK) ||
|
|
!GDALPipeRead(p, &bForce) )
|
|
break;
|
|
double dfMin = 0.0, dfMax = 0.0, dfMean = 0.0, dfStdDev = 0.0;
|
|
CPLErr eErr = poBand->GetStatistics(bApproxOK, bForce,
|
|
&dfMin, &dfMax, &dfMean, &dfStdDev);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr == CE_None )
|
|
{
|
|
GDALPipeWrite(p, dfMin);
|
|
GDALPipeWrite(p, dfMax);
|
|
GDALPipeWrite(p, dfMean);
|
|
GDALPipeWrite(p, dfStdDev);
|
|
}
|
|
}
|
|
else if( instr == INSTR_Band_ComputeStatistics )
|
|
{
|
|
int bApproxOK;
|
|
if( !GDALPipeRead(p, &bApproxOK) )
|
|
break;
|
|
double dfMin = 0.0, dfMax = 0.0, dfMean = 0.0, dfStdDev = 0.0;
|
|
CPLErr eErr = poBand->ComputeStatistics(bApproxOK,
|
|
&dfMin, &dfMax, &dfMean, &dfStdDev,
|
|
NULL, NULL);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr != CE_Failure )
|
|
{
|
|
GDALPipeWrite(p, dfMin);
|
|
GDALPipeWrite(p, dfMax);
|
|
GDALPipeWrite(p, dfMean);
|
|
GDALPipeWrite(p, dfStdDev);
|
|
}
|
|
}
|
|
else if( instr == INSTR_Band_SetStatistics )
|
|
{
|
|
double dfMin, dfMax, dfMean, dfStdDev;
|
|
if( !GDALPipeRead(p, &dfMin) ||
|
|
!GDALPipeRead(p, &dfMax) ||
|
|
!GDALPipeRead(p, &dfMean) ||
|
|
!GDALPipeRead(p, &dfStdDev) )
|
|
break;
|
|
CPLErr eErr = poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_ComputeRasterMinMax )
|
|
{
|
|
int bApproxOK;
|
|
if( !GDALPipeRead(p, &bApproxOK) )
|
|
break;
|
|
double adfMinMax[2];
|
|
CPLErr eErr = poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr != CE_Failure )
|
|
{
|
|
GDALPipeWrite(p, adfMinMax[0]);
|
|
GDALPipeWrite(p, adfMinMax[1]);
|
|
}
|
|
}
|
|
else if( instr == INSTR_Band_GetHistogram )
|
|
{
|
|
double dfMin, dfMax;
|
|
int nBuckets, bIncludeOutOfRange, bApproxOK;
|
|
if( !GDALPipeRead(p, &dfMin) ||
|
|
!GDALPipeRead(p, &dfMax) ||
|
|
!GDALPipeRead(p, &nBuckets) ||
|
|
!GDALPipeRead(p, &bIncludeOutOfRange) ||
|
|
!GDALPipeRead(p, &bApproxOK) )
|
|
break;
|
|
GUIntBig* panHistogram = (GUIntBig*) VSIMalloc2(sizeof(GUIntBig), nBuckets);
|
|
if( panHistogram == NULL )
|
|
break;
|
|
CPLErr eErr = poBand->GetHistogram(dfMin, dfMax,
|
|
nBuckets, panHistogram,
|
|
bIncludeOutOfRange, bApproxOK, NULL, NULL);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr != CE_Failure )
|
|
{
|
|
GDALPipeWrite(p, nBuckets * sizeof(GUIntBig), panHistogram);
|
|
}
|
|
CPLFree(panHistogram);
|
|
}
|
|
else if( instr == INSTR_Band_GetDefaultHistogram )
|
|
{
|
|
double dfMin, dfMax;
|
|
int nBuckets;
|
|
int bForce;
|
|
if( !GDALPipeRead(p, &bForce) )
|
|
break;
|
|
GUIntBig* panHistogram = NULL;
|
|
CPLErr eErr = poBand->GetDefaultHistogram(&dfMin, &dfMax,
|
|
&nBuckets, &panHistogram,
|
|
bForce, NULL, NULL);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
if( eErr != CE_Failure )
|
|
{
|
|
GDALPipeWrite(p, dfMin);
|
|
GDALPipeWrite(p, dfMax);
|
|
GDALPipeWrite(p, nBuckets);
|
|
GDALPipeWrite(p, nBuckets * sizeof(GUIntBig) , panHistogram);
|
|
}
|
|
CPLFree(panHistogram);
|
|
}
|
|
else if( instr == INSTR_Band_SetDefaultHistogram )
|
|
{
|
|
double dfMin, dfMax;
|
|
int nBuckets;
|
|
GUIntBig* panHistogram = NULL;
|
|
if( !GDALPipeRead(p, &dfMin) ||
|
|
!GDALPipeRead(p, &dfMax) ||
|
|
!GDALPipeRead(p, &nBuckets) ||
|
|
!GDALPipeRead(p, nBuckets, &panHistogram) )
|
|
{
|
|
CPLFree(panHistogram);
|
|
break;
|
|
}
|
|
CPLErr eErr = poBand->SetDefaultHistogram(dfMin, dfMax,
|
|
nBuckets, panHistogram);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(panHistogram);
|
|
}
|
|
else if( instr == INSTR_Band_HasArbitraryOverviews )
|
|
{
|
|
int nVal = poBand->HasArbitraryOverviews();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, nVal);
|
|
}
|
|
else if( instr == INSTR_Band_GetOverviewCount )
|
|
{
|
|
int nVal = poBand->GetOverviewCount();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, nVal);
|
|
}
|
|
else if( instr == INSTR_Band_GetOverview )
|
|
{
|
|
int iOvr;
|
|
if( !GDALPipeRead(p, &iOvr) )
|
|
break;
|
|
GDALRasterBand* poOvrBand = poBand->GetOverview(iOvr);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, aBands, poOvrBand);
|
|
}
|
|
else if( instr == INSTR_Band_GetMaskBand )
|
|
{
|
|
GDALRasterBand* poMaskBand = poBand->GetMaskBand();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, aBands, poMaskBand);
|
|
}
|
|
else if( instr == INSTR_Band_GetMaskFlags )
|
|
{
|
|
int nVal = poBand->GetMaskFlags();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, nVal);
|
|
}
|
|
else if( instr == INSTR_Band_CreateMaskBand )
|
|
{
|
|
int nFlags;
|
|
if( !GDALPipeRead(p, &nFlags) )
|
|
break;
|
|
CPLErr eErr = poBand->CreateMaskBand(nFlags);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_Fill )
|
|
{
|
|
double dfReal, dfImag;
|
|
if( !GDALPipeRead(p, &dfReal) ||
|
|
!GDALPipeRead(p, &dfImag) )
|
|
break;
|
|
CPLErr eErr = poBand->Fill(dfReal, dfImag);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_GetColorTable )
|
|
{
|
|
GDALColorTable* poColorTable = poBand->GetColorTable();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, poColorTable);
|
|
}
|
|
else if( instr == INSTR_Band_SetColorTable )
|
|
{
|
|
GDALColorTable* poColorTable = NULL;
|
|
if( !GDALPipeRead(p, &poColorTable) )
|
|
break;
|
|
CPLErr eErr = poBand->SetColorTable(poColorTable);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
delete poColorTable;
|
|
}
|
|
else if( instr == INSTR_Band_GetUnitType )
|
|
{
|
|
const char* pszVal = poBand->GetUnitType();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, pszVal);
|
|
}
|
|
else if( instr == INSTR_Band_SetUnitType )
|
|
{
|
|
char* pszUnitType = NULL;
|
|
if( !GDALPipeRead(p, &pszUnitType) )
|
|
break;
|
|
CPLErr eErr = poBand->SetUnitType(pszUnitType);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(pszUnitType);
|
|
}
|
|
else if( instr == INSTR_Band_BuildOverviews )
|
|
{
|
|
char* pszResampling = NULL;
|
|
int nOverviews;
|
|
int* panOverviewList = NULL;
|
|
if( !GDALPipeRead(p, &pszResampling) ||
|
|
!GDALPipeRead(p, &nOverviews) ||
|
|
!GDALPipeRead(p, nOverviews, &panOverviewList) )
|
|
{
|
|
CPLFree(pszResampling);
|
|
CPLFree(panOverviewList);
|
|
break;
|
|
}
|
|
CPLErr eErr = poBand->BuildOverviews(pszResampling, nOverviews,
|
|
panOverviewList, NULL, NULL);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CPLFree(pszResampling);
|
|
CPLFree(panOverviewList);
|
|
}
|
|
else if( instr == INSTR_Band_GetDefaultRAT )
|
|
{
|
|
const GDALRasterAttributeTable* poRAT = poBand->GetDefaultRAT();
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, poRAT);
|
|
}
|
|
else if( instr == INSTR_Band_SetDefaultRAT )
|
|
{
|
|
GDALRasterAttributeTable* poRAT = NULL;
|
|
if( !GDALPipeRead(p, &poRAT) )
|
|
break;
|
|
CPLErr eErr = poBand->SetDefaultRAT(poRAT);
|
|
delete poRAT;
|
|
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
}
|
|
else if( instr == INSTR_Band_AdviseRead )
|
|
{
|
|
int nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize;
|
|
int nDT;
|
|
char** papszOptions = NULL;
|
|
if( !GDALPipeRead(p, &nXOff) ||
|
|
!GDALPipeRead(p, &nYOff) ||
|
|
!GDALPipeRead(p, &nXSize) ||
|
|
!GDALPipeRead(p, &nYSize) ||
|
|
!GDALPipeRead(p, &nBufXSize) ||
|
|
!GDALPipeRead(p, &nBufYSize) ||
|
|
!GDALPipeRead(p, &nDT) ||
|
|
!GDALPipeRead(p, &papszOptions) )
|
|
break;
|
|
CPLErr eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
|
|
(GDALDataType)nDT, papszOptions);
|
|
GDALEmitEndOfJunkMarker(p);
|
|
GDALPipeWrite(p, eErr);
|
|
CSLDestroy(papszOptions);
|
|
}
|
|
|
|
if( poSrcDS == NULL )
|
|
{
|
|
GDALPipeWrite(p, (int)aoErrors.size());
|
|
for(int i=0;i<(int)aoErrors.size();i++)
|
|
{
|
|
GDALPipeWrite(p, aoErrors[i].eErr);
|
|
GDALPipeWrite(p, aoErrors[i].nErrNo);
|
|
GDALPipeWrite(p, aoErrors[i].osErrorMsg);
|
|
}
|
|
aoErrors.resize(0);
|
|
}
|
|
else
|
|
GDALPipeWrite(p, 0);
|
|
}
|
|
|
|
if( poSrcDS == NULL )
|
|
CPLPopErrorHandler();
|
|
|
|
CPLSetThreadLocalConfigOption("GDAL_API_PROXY", pszOldValDup);
|
|
CPLFree(pszOldValDup);
|
|
|
|
// fprintf(stderr, "[%d] finished = %d\n", (int)getpid(), nRet);
|
|
|
|
if( poSrcDS == NULL && poDS != NULL )
|
|
GDALClose((GDALDatasetH)poDS);
|
|
|
|
CPLFree(pBuffer);
|
|
|
|
CPLFree(asyncp.pszProgressMsg);
|
|
if( asyncp.hMutex )
|
|
CPLDestroyMutex(asyncp.hMutex);
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALServerLoop() */
|
|
/************************************************************************/
|
|
|
|
int GDALServerLoop(CPL_FILE_HANDLE fin, CPL_FILE_HANDLE fout)
|
|
{
|
|
#ifndef WIN32
|
|
unsetenv("CPL_SHOW_MEM_STATS");
|
|
#endif
|
|
CPLSetConfigOption("GDAL_API_PROXY", "NO");
|
|
|
|
GDALPipe* p = GDALPipeBuild(fin, fout);
|
|
|
|
int nRet = GDALServerLoop(p, NULL, NULL, NULL);
|
|
|
|
GDALPipeFree(p);
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALServerLoopSocket() */
|
|
/************************************************************************/
|
|
|
|
int GDALServerLoopSocket(CPL_SOCKET nSocket)
|
|
{
|
|
#ifndef WIN32
|
|
unsetenv("CPL_SHOW_MEM_STATS");
|
|
#endif
|
|
CPLSetConfigOption("GDAL_API_PROXY", "NO");
|
|
|
|
GDALPipe* p = GDALPipeBuild(nSocket);
|
|
|
|
int nRet = GDALServerLoop(p, NULL, NULL, NULL);
|
|
|
|
GDALPipeFree(p);
|
|
|
|
return nRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALClientDataset() */
|
|
/************************************************************************/
|
|
|
|
GDALClientDataset::GDALClientDataset(GDALServerSpawnedProcess* ssp)
|
|
{
|
|
this->ssp = ssp;
|
|
this->p = ssp->p;
|
|
bFreeDriver = FALSE;
|
|
nGCPCount = 0;
|
|
pasGCPs = NULL;
|
|
async = NULL;
|
|
memset(abyCaps, 0, sizeof(abyCaps));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALClientDataset() */
|
|
/************************************************************************/
|
|
|
|
GDALClientDataset::GDALClientDataset(GDALPipe* p)
|
|
{
|
|
this->ssp = NULL;
|
|
this->p = p;
|
|
bFreeDriver = FALSE;
|
|
nGCPCount = 0;
|
|
pasGCPs = NULL;
|
|
async = NULL;
|
|
memset(abyCaps, 0, sizeof(abyCaps));
|
|
}
|
|
/************************************************************************/
|
|
/* ~GDALClientDataset() */
|
|
/************************************************************************/
|
|
|
|
GDALClientDataset::~GDALClientDataset()
|
|
{
|
|
FlushCache();
|
|
|
|
ProcessAsyncProgress();
|
|
|
|
std::map<CPLString, char**>::iterator oIter = aoMapMetadata.begin();
|
|
for( ; oIter != aoMapMetadata.end(); ++oIter )
|
|
CSLDestroy(oIter->second);
|
|
|
|
std::map< std::pair<CPLString,CPLString>, char*>::iterator oIterItem =
|
|
aoMapMetadataItem.begin();
|
|
for( ; oIterItem != aoMapMetadataItem.end(); ++oIterItem )
|
|
CPLFree(oIterItem->second);
|
|
|
|
if( nGCPCount > 0 )
|
|
{
|
|
GDALDeinitGCPs(nGCPCount, pasGCPs);
|
|
CPLFree(pasGCPs);
|
|
}
|
|
|
|
if( ssp != NULL )
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
if( bFreeDriver )
|
|
delete poDriver;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ProcessAsyncProgress() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientDataset::ProcessAsyncProgress()
|
|
{
|
|
if( !async ) return TRUE;
|
|
CPLMutexHolderD(&(async->hMutex));
|
|
if( !async->bUpdated ) return async->bRet;
|
|
async->bUpdated = FALSE;
|
|
if( !GDALPipeWrite(p, INSTR_Progress) ||
|
|
!GDALPipeWrite(p, async->dfComplete) ||
|
|
!GDALPipeWrite(p, async->pszProgressMsg) )
|
|
return TRUE;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return TRUE;
|
|
|
|
int bRet = TRUE;
|
|
if( !GDALPipeRead(p, &bRet) )
|
|
return TRUE;
|
|
async->bRet = bRet;
|
|
GDALConsumeErrors(p);
|
|
return bRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IBuildOverviews() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::IBuildOverviews( const char *pszResampling,
|
|
int nOverviews, int *panOverviewList,
|
|
int nListBands, int *panBandList,
|
|
GDALProgressFunc pfnProgress,
|
|
void * pProgressData )
|
|
{
|
|
if( !SupportsInstr(INSTR_IBuildOverviews) )
|
|
return GDALPamDataset::IBuildOverviews(pszResampling, nOverviews, panOverviewList,
|
|
nListBands, panBandList,
|
|
pfnProgress, pProgressData);
|
|
|
|
CLIENT_ENTER();
|
|
if( nOverviews < 0 || nOverviews > 1000 ||
|
|
nListBands < 0 || nListBands > GetRasterCount() )
|
|
return CE_Failure;
|
|
|
|
GDALPipeWriteConfigOption(p, "BIGTIFF_OVERVIEW");
|
|
GDALPipeWriteConfigOption(p, "COMPRESS_OVERVIEW");
|
|
GDALPipeWriteConfigOption(p, "PREDICTOR_OVERVIEW");
|
|
GDALPipeWriteConfigOption(p, "JPEG_QUALITY_OVERVIEW");
|
|
GDALPipeWriteConfigOption(p, "PHOTOMETRIC_OVERVIEW");
|
|
GDALPipeWriteConfigOption(p, "USE_RRD");
|
|
GDALPipeWriteConfigOption(p, "HFA_USE_RRD");
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_OVR_BLOCKSIZE");
|
|
GDALPipeWriteConfigOption(p, "GTIFF_DONT_WRITE_BLOCKS");
|
|
|
|
if( !GDALPipeWrite(p, INSTR_IBuildOverviews) ||
|
|
!GDALPipeWrite(p, pszResampling) ||
|
|
!GDALPipeWrite(p, nOverviews) ||
|
|
!GDALPipeWrite(p, nOverviews * sizeof(int), panOverviewList) ||
|
|
!GDALPipeWrite(p, nListBands) ||
|
|
!GDALPipeWrite(p, nListBands * sizeof(int), panBandList) )
|
|
return CE_Failure;
|
|
|
|
if( GDALServerLoop(p, NULL, pfnProgress, pProgressData) != 0 )
|
|
{
|
|
GDALConsumeErrors(p);
|
|
return CE_Failure;
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
|
|
for(int i=0; i<nBands;i++)
|
|
((GDALClientRasterBand*)papoBands[i])->ClearOverviewCache();
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IRasterIO() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::IRasterIO( GDALRWFlag eRWFlag,
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
int nBandCount, int *panBandMap,
|
|
GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
|
|
GDALRasterIOExtraArg* psExtraArg)
|
|
{
|
|
if( !SupportsInstr(( eRWFlag == GF_Read ) ? INSTR_IRasterIO_Read : INSTR_IRasterIO_Write ) )
|
|
return GDALPamDataset::IRasterIO( eRWFlag,
|
|
nXOff, nYOff, nXSize, nYSize,
|
|
pData, nBufXSize, nBufYSize,
|
|
eBufType,
|
|
nBandCount, panBandMap,
|
|
nPixelSpace, nLineSpace, nBandSpace,
|
|
psExtraArg );
|
|
|
|
CLIENT_ENTER();
|
|
CPLErr eRet = CE_Failure;
|
|
|
|
ProcessAsyncProgress();
|
|
|
|
int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
|
|
int bDirectCopy;
|
|
if( nPixelSpace == nDataTypeSize &&
|
|
nLineSpace == nBufXSize * nDataTypeSize &&
|
|
(nBandSpace == nBufYSize * nLineSpace ||
|
|
(nBandSpace == 0 && nBandCount == 1)) )
|
|
{
|
|
bDirectCopy = TRUE;
|
|
}
|
|
else if( nBandCount > 1 &&
|
|
nPixelSpace == nBandCount * nDataTypeSize &&
|
|
nLineSpace == nBufXSize * nPixelSpace &&
|
|
nBandSpace == nBandCount )
|
|
{
|
|
bDirectCopy = TRUE;
|
|
}
|
|
else
|
|
bDirectCopy = FALSE;
|
|
|
|
if( eRWFlag == GF_Write )
|
|
{
|
|
for(int i=0;i<nBands;i++)
|
|
((GDALClientRasterBand*)GetRasterBand(i+1))->InvalidateCachedLines();
|
|
}
|
|
|
|
if( !GDALPipeWrite(p, ( eRWFlag == GF_Read ) ? INSTR_IRasterIO_Read : INSTR_IRasterIO_Write ) ||
|
|
!GDALPipeWrite(p, nXOff) ||
|
|
!GDALPipeWrite(p, nYOff) ||
|
|
!GDALPipeWrite(p, nXSize) ||
|
|
!GDALPipeWrite(p, nYSize) ||
|
|
!GDALPipeWrite(p, nBufXSize) ||
|
|
!GDALPipeWrite(p, nBufYSize) ||
|
|
!GDALPipeWrite(p, eBufType) ||
|
|
!GDALPipeWrite(p, nBandCount) ||
|
|
!GDALPipeWrite(p, nBandCount * sizeof(int), panBandMap) )
|
|
return CE_Failure;
|
|
|
|
if( bDirectCopy )
|
|
{
|
|
if( !GDALPipeWrite(p, nPixelSpace) ||
|
|
!GDALPipeWrite(p, nLineSpace) ||
|
|
!GDALPipeWrite(p, nBandSpace) )
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
if( !GDALPipeWrite(p, nPixelSpace * 0) ||
|
|
!GDALPipeWrite(p, nLineSpace * 0) ||
|
|
!GDALPipeWrite(p, nBandSpace * 0) )
|
|
return CE_Failure;
|
|
}
|
|
|
|
if( eRWFlag == GF_Read )
|
|
{
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet != CE_Failure )
|
|
{
|
|
int nSize;
|
|
if( !GDALPipeRead(p, &nSize) )
|
|
return CE_Failure;
|
|
GIntBig nExpectedSize = (GIntBig)nBufXSize * nBufYSize * nBandCount * nDataTypeSize;
|
|
if( nSize != nExpectedSize )
|
|
return CE_Failure;
|
|
if( bDirectCopy )
|
|
{
|
|
if( !GDALPipeRead_nolength(p, nSize, pData) )
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
GByte* pBuf = (GByte*)VSIMalloc(nSize);
|
|
if( pBuf == NULL )
|
|
return CE_Failure;
|
|
if( !GDALPipeRead_nolength(p, nSize, pBuf) )
|
|
{
|
|
VSIFree(pBuf);
|
|
return CE_Failure;
|
|
}
|
|
for(int iBand=0;iBand<nBandCount;iBand++)
|
|
{
|
|
for(int j=0;j<nBufYSize;j++)
|
|
{
|
|
GDALCopyWords( pBuf + (iBand * nBufYSize + j) * nBufXSize * nDataTypeSize,
|
|
eBufType, nDataTypeSize,
|
|
(GByte*)pData + iBand * nBandSpace + j * nLineSpace,
|
|
eBufType, nPixelSpace,
|
|
nBufXSize);
|
|
}
|
|
}
|
|
VSIFree(pBuf);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GIntBig nSizeBig = (GIntBig)nBufXSize * nBufYSize * nBandCount * nDataTypeSize;
|
|
int nSize = (int)nSizeBig;
|
|
if( nSizeBig != nSize )
|
|
return CE_Failure;
|
|
if( bDirectCopy )
|
|
{
|
|
if( !GDALPipeWrite(p, nSize, pData) )
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
GByte* pBuf = (GByte*)VSIMalloc(nSize);
|
|
if( pBuf == NULL )
|
|
return CE_Failure;
|
|
for(int iBand=0;iBand<nBandCount;iBand++)
|
|
{
|
|
for(int j=0;j<nBufYSize;j++)
|
|
{
|
|
GDALCopyWords( (GByte*)pData + iBand * nBandSpace + j * nLineSpace,
|
|
eBufType, nPixelSpace,
|
|
pBuf + (iBand * nBufYSize + j) * nBufXSize * nDataTypeSize,
|
|
eBufType, nDataTypeSize,
|
|
nBufXSize );
|
|
}
|
|
}
|
|
if( !GDALPipeWrite(p, nSize, pBuf) )
|
|
{
|
|
VSIFree(pBuf);
|
|
return CE_Failure;
|
|
}
|
|
VSIFree(pBuf);
|
|
}
|
|
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::GetGeoTransform( double * padfTransform )
|
|
{
|
|
if( !SupportsInstr(INSTR_GetGeoTransform) )
|
|
return GDALPamDataset::GetGeoTransform(padfTransform);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_GetGeoTransform) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet != CE_Failure )
|
|
{
|
|
if( !GDALPipeRead(p, 6 * sizeof(double), padfTransform) )
|
|
return CE_Failure;
|
|
}
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::SetGeoTransform( double * padfTransform )
|
|
{
|
|
if( !SupportsInstr(INSTR_SetGeoTransform) )
|
|
return GDALPamDataset::SetGeoTransform(padfTransform);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_SetGeoTransform) ||
|
|
!GDALPipeWrite(p, 6 * sizeof(double), padfTransform) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetProjectionRef() */
|
|
/************************************************************************/
|
|
|
|
const char* GDALClientDataset::GetProjectionRef()
|
|
{
|
|
if( !SupportsInstr(INSTR_GetProjectionRef) )
|
|
return GDALPamDataset::GetProjectionRef();
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_GetProjectionRef) )
|
|
return osProjection;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return osProjection;
|
|
|
|
char* pszStr = NULL;
|
|
if( !GDALPipeRead(p, &pszStr) )
|
|
return osProjection;
|
|
GDALConsumeErrors(p);
|
|
if( pszStr == NULL )
|
|
return NULL;
|
|
osProjection = pszStr;
|
|
CPLFree(pszStr);
|
|
return osProjection;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetProjection() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::SetProjection(const char* pszProjection)
|
|
{
|
|
if( !SupportsInstr(INSTR_SetProjection) )
|
|
return GDALPamDataset::SetProjection(pszProjection);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_SetProjection) ||
|
|
!GDALPipeWrite(p, pszProjection))
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPCount() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientDataset::GetGCPCount()
|
|
{
|
|
if( !SupportsInstr(INSTR_GetGCPCount) )
|
|
return GDALPamDataset::GetGCPCount();
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_GetGCPCount) )
|
|
return 0;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return 0;
|
|
|
|
int nGCPCount;
|
|
if( !GDALPipeRead(p, &nGCPCount) )
|
|
return 0;
|
|
GDALConsumeErrors(p);
|
|
return nGCPCount;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPProjection() */
|
|
/************************************************************************/
|
|
|
|
const char * GDALClientDataset::GetGCPProjection()
|
|
{
|
|
if( !SupportsInstr(INSTR_GetGCPProjection) )
|
|
return GDALPamDataset::GetGCPProjection();
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_GetGCPProjection) )
|
|
return osGCPProjection;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return osGCPProjection;
|
|
|
|
char* pszStr = NULL;
|
|
if( !GDALPipeRead(p, &pszStr) )
|
|
return osGCPProjection;
|
|
GDALConsumeErrors(p);
|
|
if( pszStr == NULL )
|
|
return NULL;
|
|
osGCPProjection = pszStr;
|
|
CPLFree(pszStr);
|
|
return osGCPProjection;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPs() */
|
|
/************************************************************************/
|
|
|
|
const GDAL_GCP * GDALClientDataset::GetGCPs()
|
|
{
|
|
if( !SupportsInstr(INSTR_GetGCPs) )
|
|
return GDALPamDataset::GetGCPs();
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_GetGCPs) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
if( nGCPCount > 0 )
|
|
{
|
|
GDALDeinitGCPs(nGCPCount, pasGCPs);
|
|
CPLFree(pasGCPs);
|
|
pasGCPs = NULL;
|
|
}
|
|
nGCPCount = 0;
|
|
|
|
if( !GDALPipeRead(p, &nGCPCount, &pasGCPs) )
|
|
return NULL;
|
|
|
|
GDALConsumeErrors(p);
|
|
return pasGCPs;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetGCPs() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
|
|
const char *pszGCPProjection )
|
|
{
|
|
if( !SupportsInstr(INSTR_SetGCPs) )
|
|
return GDALPamDataset::SetGCPs(nGCPCount, pasGCPList, pszGCPProjection);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_SetGCPs) ||
|
|
!GDALPipeWrite(p, nGCPCount, pasGCPList) ||
|
|
!GDALPipeWrite(p, pszGCPProjection) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFileList() */
|
|
/************************************************************************/
|
|
|
|
char** GDALClientDataset::GetFileList()
|
|
{
|
|
if( !SupportsInstr(INSTR_GetFileList) )
|
|
return GDALPamDataset::GetFileList();
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_GetFileList) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
char** papszFileList = NULL;
|
|
if( !GDALPipeRead(p, &papszFileList) )
|
|
return NULL;
|
|
GDALConsumeErrors(p);
|
|
|
|
/* If server is Windows and client is Unix, then replace backslahes */
|
|
/* by slashes */
|
|
#ifndef WIN32
|
|
char** papszIter = papszFileList;
|
|
while( papszIter != NULL && *papszIter != NULL )
|
|
{
|
|
char* pszIter = *papszIter;
|
|
char* pszBackSlash;
|
|
while( (pszBackSlash = strchr(pszIter, '\\')) != NULL )
|
|
{
|
|
*pszBackSlash = '/';
|
|
pszIter = pszBackSlash + 1;
|
|
}
|
|
papszIter ++;
|
|
}
|
|
#endif
|
|
|
|
return papszFileList;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadata() */
|
|
/************************************************************************/
|
|
|
|
char** GDALClientDataset::GetMetadata( const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_GetMetadata) )
|
|
return GDALPamDataset::GetMetadata(pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( pszDomain == NULL )
|
|
pszDomain = "";
|
|
std::map<CPLString, char**>::iterator oIter = aoMapMetadata.find(CPLString(pszDomain));
|
|
if( oIter != aoMapMetadata.end() )
|
|
{
|
|
CSLDestroy(oIter->second);
|
|
aoMapMetadata.erase(oIter);
|
|
}
|
|
if( !GDALPipeWrite(p, INSTR_GetMetadata) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
char** papszMD = NULL;
|
|
if( !GDALPipeRead(p, &papszMD) )
|
|
return NULL;
|
|
aoMapMetadata[pszDomain] = papszMD;
|
|
GDALConsumeErrors(p);
|
|
return papszMD;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetDescription() */
|
|
/************************************************************************/
|
|
|
|
/*void GDALClientDataset::SetDescription( const char * pszDescription )
|
|
{
|
|
sDescription = pszDescription;
|
|
if( !GDALPipeWrite(p, INSTR_SetDescription) ||
|
|
!GDALPipeWrite(p, pszDescription) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p))
|
|
return;
|
|
GDALConsumeErrors(p);
|
|
}*/
|
|
|
|
/************************************************************************/
|
|
/* GetMetadataItem() */
|
|
/************************************************************************/
|
|
|
|
const char* GDALClientDataset::GetMetadataItem( const char * pszName,
|
|
const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_GetMetadataItem) )
|
|
return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( pszDomain == NULL )
|
|
pszDomain = "";
|
|
std::pair<CPLString,CPLString> oPair =
|
|
std::pair<CPLString,CPLString> (CPLString(pszDomain), CPLString(pszName));
|
|
std::map< std::pair<CPLString,CPLString>, char*>::iterator oIter =
|
|
aoMapMetadataItem.find(oPair);
|
|
if( oIter != aoMapMetadataItem.end() )
|
|
{
|
|
CPLFree(oIter->second);
|
|
aoMapMetadataItem.erase(oIter);
|
|
}
|
|
if( !GDALPipeWrite(p, INSTR_GetMetadataItem) ||
|
|
!GDALPipeWrite(p, pszName) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
char* pszItem = NULL;
|
|
if( !GDALPipeRead(p, &pszItem) )
|
|
return NULL;
|
|
aoMapMetadataItem[oPair] = pszItem;
|
|
GDALConsumeErrors(p);
|
|
return pszItem;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadata() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::SetMetadata( char ** papszMetadata,
|
|
const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_SetMetadata) )
|
|
return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_SetMetadata) ||
|
|
!GDALPipeWrite(p, papszMetadata) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetMetadataItem() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::SetMetadataItem( const char * pszName,
|
|
const char * pszValue,
|
|
const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_SetMetadataItem) )
|
|
return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_SetMetadataItem) ||
|
|
!GDALPipeWrite(p, pszName) ||
|
|
!GDALPipeWrite(p, pszValue) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* FlushCache() */
|
|
/************************************************************************/
|
|
|
|
void GDALClientDataset::FlushCache()
|
|
{
|
|
if( !SupportsInstr(INSTR_FlushCache) )
|
|
{
|
|
GDALPamDataset::FlushCache();
|
|
return;
|
|
}
|
|
|
|
for(int i=0;i<nBands;i++)
|
|
((GDALClientRasterBand*)GetRasterBand(i+1))->InvalidateCachedLines();
|
|
|
|
CLIENT_ENTER();
|
|
SetPamFlags(0);
|
|
GDALPamDataset::FlushCache();
|
|
if( !GDALPipeWrite(p, INSTR_FlushCache) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p) )
|
|
return;
|
|
GDALConsumeErrors(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AddBand() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::AddBand( GDALDataType eType,
|
|
char **papszOptions )
|
|
{
|
|
if( !SupportsInstr(INSTR_AddBand) )
|
|
return GDALPamDataset::AddBand(eType, papszOptions);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_AddBand) ||
|
|
!GDALPipeWrite(p, eType) ||
|
|
!GDALPipeWrite(p, papszOptions) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet == CE_None )
|
|
{
|
|
GDALRasterBand* poBand = NULL;
|
|
if( !GDALPipeRead(p, this, &poBand, abyCaps) )
|
|
return CE_Failure;
|
|
SetBand(GetRasterCount() + 1, poBand);
|
|
}
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* AdviseRead() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
|
|
int nBufXSize, int nBufYSize,
|
|
GDALDataType eDT,
|
|
int nBandCount, int *panBandList,
|
|
char **papszOptions )
|
|
{
|
|
if( !SupportsInstr(INSTR_AdviseRead) )
|
|
return GDALPamDataset::AdviseRead(nXOff, nYOff, nXSize, nYSize,
|
|
nBufXSize, nBufYSize, eDT, nBandCount, panBandList,
|
|
papszOptions);
|
|
|
|
CLIENT_ENTER();
|
|
if( !GDALPipeWrite(p, INSTR_AdviseRead) ||
|
|
!GDALPipeWrite(p, nXOff) ||
|
|
!GDALPipeWrite(p, nYOff) ||
|
|
!GDALPipeWrite(p, nXSize) ||
|
|
!GDALPipeWrite(p, nYSize) ||
|
|
!GDALPipeWrite(p, nBufXSize) ||
|
|
!GDALPipeWrite(p, nBufYSize) ||
|
|
!GDALPipeWrite(p, eDT) ||
|
|
!GDALPipeWrite(p, nBandCount) ||
|
|
!GDALPipeWrite(p, panBandList ? nBandCount * sizeof(int) : 0, panBandList) ||
|
|
!GDALPipeWrite(p, papszOptions) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateMaskBand() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::CreateMaskBand( int nFlags )
|
|
{
|
|
if( !SupportsInstr(INSTR_CreateMaskBand) )
|
|
return GDALPamDataset::CreateMaskBand(nFlags);
|
|
|
|
CLIENT_ENTER();
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_INTERNAL_MASK", bRecycleChild);
|
|
if( !GDALPipeWrite(p, INSTR_CreateMaskBand) ||
|
|
!GDALPipeWrite(p, nFlags) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALClientRasterBand() */
|
|
/************************************************************************/
|
|
|
|
GDALClientRasterBand::GDALClientRasterBand(GDALPipe* p, int iSrvBand,
|
|
GDALClientDataset* poDS,
|
|
int nBand, GDALAccess eAccess,
|
|
int nRasterXSize, int nRasterYSize,
|
|
GDALDataType eDataType,
|
|
int nBlockXSize, int nBlockYSize,
|
|
GByte abyCapsIn[16])
|
|
{
|
|
this->p = p;
|
|
this->iSrvBand = iSrvBand;
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
this->eAccess = eAccess;
|
|
this->nRasterXSize = nRasterXSize;
|
|
this->nRasterYSize = nRasterYSize;
|
|
this->eDataType = eDataType;
|
|
this->nBlockXSize = nBlockXSize;
|
|
this->nBlockYSize = nBlockYSize;
|
|
papszCategoryNames = NULL;
|
|
poColorTable = NULL;
|
|
pszUnitType = NULL;
|
|
poMaskBand = NULL;
|
|
poRAT = NULL;
|
|
memcpy(abyCaps, abyCapsIn, sizeof(abyCaps));
|
|
bEnableLineCaching = CSLTestBoolean(CPLGetConfigOption("GDAL_API_PROXY_LINE_CACHING", "YES"));
|
|
nSuccessiveLinesRead = 0;
|
|
eLastBufType = GDT_Unknown;
|
|
nLastYOff = -1;
|
|
pabyCachedLines = NULL;
|
|
eCachedBufType = GDT_Unknown;
|
|
nCachedYStart = -1;
|
|
nCachedLines = 0;
|
|
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~GDALClientRasterBand() */
|
|
/************************************************************************/
|
|
|
|
GDALClientRasterBand::~GDALClientRasterBand()
|
|
{
|
|
CSLDestroy(papszCategoryNames);
|
|
delete poColorTable;
|
|
CPLFree(pszUnitType);
|
|
delete poMaskBand;
|
|
delete poRAT;
|
|
CPLFree(pabyCachedLines);
|
|
|
|
std::map<int, GDALRasterBand*>::iterator oIter = aMapOvrBands.begin();
|
|
for( ; oIter != aMapOvrBands.end(); ++oIter )
|
|
delete oIter->second;
|
|
|
|
std::map< std::pair<CPLString,CPLString>, char*>::iterator oIterItem =
|
|
aoMapMetadataItem.begin();
|
|
for( ; oIterItem != aoMapMetadataItem.end(); ++oIterItem )
|
|
CPLFree(oIterItem->second);
|
|
|
|
std::map<CPLString, char**>::iterator oIterMD = aoMapMetadata.begin();
|
|
for( ; oIterMD != aoMapMetadata.end(); ++oIterMD )
|
|
CSLDestroy(oIterMD->second);
|
|
|
|
for(int i=0; i < (int)apoOldMaskBands.size(); i++)
|
|
delete apoOldMaskBands[i];
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateFakeMaskBand() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand* GDALClientRasterBand::CreateFakeMaskBand()
|
|
{
|
|
if( poMaskBand == NULL )
|
|
poMaskBand = new GDALAllValidMaskBand(this);
|
|
return poMaskBand;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* WriteInstr() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientRasterBand::WriteInstr(InstrEnum instr)
|
|
{
|
|
return GDALPipeWrite(p, instr) &&
|
|
GDALPipeWrite(p, iSrvBand);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* FlushCache() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::FlushCache()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_FlushCache) )
|
|
return GDALPamRasterBand::FlushCache();
|
|
|
|
InvalidateCachedLines();
|
|
|
|
CLIENT_ENTER();
|
|
CPLErr eErr = GDALPamRasterBand::FlushCache();
|
|
if( eErr == CE_None )
|
|
{
|
|
if( !WriteInstr(INSTR_Band_FlushCache) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
return eErr;
|
|
}
|
|
/************************************************************************/
|
|
/* GetCategoryNames() */
|
|
/************************************************************************/
|
|
|
|
char ** GDALClientRasterBand::GetCategoryNames()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetCategoryNames) )
|
|
return GDALPamRasterBand::GetCategoryNames();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetCategoryNames) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
CSLDestroy(papszCategoryNames);
|
|
papszCategoryNames = NULL;
|
|
if( !GDALPipeRead(p, &papszCategoryNames) )
|
|
return NULL;
|
|
GDALConsumeErrors(p);
|
|
return papszCategoryNames;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetCategoryNames() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetCategoryNames( char ** papszCategoryNames )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetCategoryNames) )
|
|
return GDALPamRasterBand::SetCategoryNames(papszCategoryNames);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetCategoryNames) ||
|
|
!GDALPipeWrite(p, papszCategoryNames) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetDescription() */
|
|
/************************************************************************/
|
|
|
|
void GDALClientRasterBand::SetDescription( const char * pszDescription )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetDescription) )
|
|
{
|
|
GDALPamRasterBand::SetDescription(pszDescription);
|
|
return;
|
|
}
|
|
|
|
CLIENT_ENTER();
|
|
sDescription = pszDescription;
|
|
if( !WriteInstr(INSTR_Band_SetDescription) ||
|
|
!GDALPipeWrite(p, pszDescription) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p))
|
|
return;
|
|
GDALConsumeErrors(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadata() */
|
|
/************************************************************************/
|
|
|
|
char** GDALClientRasterBand::GetMetadata( const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetMetadata) )
|
|
return GDALPamRasterBand::GetMetadata(pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( pszDomain == NULL )
|
|
pszDomain = "";
|
|
std::map<CPLString, char**>::iterator oIter = aoMapMetadata.find(CPLString(pszDomain));
|
|
if( oIter != aoMapMetadata.end() )
|
|
{
|
|
CSLDestroy(oIter->second);
|
|
aoMapMetadata.erase(oIter);
|
|
}
|
|
if( !WriteInstr(INSTR_Band_GetMetadata) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
char** papszMD = NULL;
|
|
if( !GDALPipeRead(p, &papszMD) )
|
|
return NULL;
|
|
aoMapMetadata[pszDomain] = papszMD;
|
|
GDALConsumeErrors(p);
|
|
return papszMD;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadataItem() */
|
|
/************************************************************************/
|
|
|
|
const char* GDALClientRasterBand::GetMetadataItem( const char * pszName,
|
|
const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetMetadataItem) )
|
|
return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( pszDomain == NULL )
|
|
pszDomain = "";
|
|
std::pair<CPLString,CPLString> oPair =
|
|
std::pair<CPLString,CPLString> (CPLString(pszDomain), CPLString(pszName));
|
|
std::map< std::pair<CPLString,CPLString>, char*>::iterator oIter =
|
|
aoMapMetadataItem.find(oPair);
|
|
if( oIter != aoMapMetadataItem.end() )
|
|
{
|
|
CPLFree(oIter->second);
|
|
aoMapMetadataItem.erase(oIter);
|
|
}
|
|
if( !WriteInstr(INSTR_Band_GetMetadataItem) ||
|
|
!GDALPipeWrite(p, pszName) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
char* pszItem = NULL;
|
|
if( !GDALPipeRead(p, &pszItem) )
|
|
return NULL;
|
|
aoMapMetadataItem[oPair] = pszItem;
|
|
GDALConsumeErrors(p);
|
|
return pszItem;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetMetadata() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetMetadata( char ** papszMetadata,
|
|
const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetMetadata) )
|
|
return GDALPamRasterBand::SetMetadata(papszMetadata, pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetMetadata) ||
|
|
!GDALPipeWrite(p, papszMetadata) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetMetadataItem() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetMetadataItem( const char * pszName,
|
|
const char * pszValue,
|
|
const char * pszDomain )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetMetadataItem) )
|
|
return GDALPamRasterBand::SetMetadataItem(pszName, pszValue, pszDomain);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetMetadataItem) ||
|
|
!GDALPipeWrite(p, pszName) ||
|
|
!GDALPipeWrite(p, pszValue) ||
|
|
!GDALPipeWrite(p, pszDomain) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
GDALColorInterp GDALClientRasterBand::GetColorInterpretation()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetColorInterpretation) )
|
|
return GDALPamRasterBand::GetColorInterpretation();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetColorInterpretation) )
|
|
return GCI_Undefined;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return GCI_Undefined;
|
|
|
|
int nInt;
|
|
if( !GDALPipeRead(p, &nInt) )
|
|
return GCI_Undefined;
|
|
GDALConsumeErrors(p);
|
|
return (GDALColorInterp)nInt;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetColorInterpretation(GDALColorInterp eInterp)
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetColorInterpretation) )
|
|
return GDALPamRasterBand::SetColorInterpretation(eInterp);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetColorInterpretation) ||
|
|
!GDALPipeWrite(p, eInterp) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetStatistics() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::GetStatistics( int bApproxOK, int bForce,
|
|
double *pdfMin, double *pdfMax,
|
|
double *pdfMean, double *pdfStdDev )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetStatistics) )
|
|
return GDALPamRasterBand::GetStatistics(
|
|
bApproxOK, bForce, pdfMin, pdfMax, pdfMean, pdfStdDev);
|
|
|
|
CLIENT_ENTER();
|
|
if( !bApproxOK && CSLTestBoolean(CPLGetConfigOption("GDAL_API_PROXY_FORCE_APPROX", "NO")) )
|
|
bApproxOK = TRUE;
|
|
CPLErr eDefaultRet = CE_Failure;
|
|
if( CSLTestBoolean(CPLGetConfigOption("QGIS_HACK", "NO")) )
|
|
{
|
|
if( pdfMin ) *pdfMin = 0;
|
|
if( pdfMax ) *pdfMax = 255;
|
|
if( pdfMean ) *pdfMean = 0;
|
|
if( pdfStdDev ) *pdfStdDev = 0;
|
|
eDefaultRet = CE_None;
|
|
}
|
|
if( !WriteInstr( INSTR_Band_GetStatistics) ||
|
|
!GDALPipeWrite(p, bApproxOK) ||
|
|
!GDALPipeWrite(p, bForce) )
|
|
return eDefaultRet;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return eDefaultRet;
|
|
|
|
CPLErr eRet = eDefaultRet;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet == CE_None )
|
|
{
|
|
double dfMin, dfMax, dfMean, dfStdDev;
|
|
if( !GDALPipeRead(p, &dfMin) ||
|
|
!GDALPipeRead(p, &dfMax) ||
|
|
!GDALPipeRead(p, &dfMean) ||
|
|
!GDALPipeRead(p, &dfStdDev) )
|
|
return eDefaultRet;
|
|
if( pdfMin ) *pdfMin = dfMin;
|
|
if( pdfMax ) *pdfMax = dfMax;
|
|
if( pdfMean ) *pdfMean = dfMean;
|
|
if( pdfStdDev ) *pdfStdDev = dfStdDev;
|
|
}
|
|
else if( eDefaultRet == CE_None )
|
|
eRet = eDefaultRet;
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ComputeStatistics() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::ComputeStatistics( int bApproxOK,
|
|
double *pdfMin,
|
|
double *pdfMax,
|
|
double *pdfMean,
|
|
double *pdfStdDev,
|
|
GDALProgressFunc pfnProgress,
|
|
void *pProgressData )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_ComputeStatistics) )
|
|
return GDALPamRasterBand::ComputeStatistics(
|
|
bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev, pfnProgress, pProgressData);
|
|
|
|
CLIENT_ENTER();
|
|
if( !bApproxOK && CSLTestBoolean(CPLGetConfigOption("GDAL_API_PROXY_FORCE_APPROX", "NO")) )
|
|
bApproxOK = TRUE;
|
|
if( !WriteInstr(INSTR_Band_ComputeStatistics) ||
|
|
!GDALPipeWrite(p, bApproxOK) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet != CE_Failure )
|
|
{
|
|
double dfMin, dfMax, dfMean, dfStdDev;
|
|
if( !GDALPipeRead(p, &dfMin) ||
|
|
!GDALPipeRead(p, &dfMax) ||
|
|
!GDALPipeRead(p, &dfMean) ||
|
|
!GDALPipeRead(p, &dfStdDev) )
|
|
return CE_Failure;
|
|
if( pdfMin ) *pdfMin = dfMin;
|
|
if( pdfMax ) *pdfMax = dfMax;
|
|
if( pdfMean ) *pdfMean = dfMean;
|
|
if( pdfStdDev ) *pdfStdDev = dfStdDev;
|
|
}
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetStatistics() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetStatistics( double dfMin, double dfMax,
|
|
double dfMean, double dfStdDev )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetStatistics) )
|
|
return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetStatistics) ||
|
|
!GDALPipeWrite(p, dfMin) ||
|
|
!GDALPipeWrite(p, dfMax) ||
|
|
!GDALPipeWrite(p, dfMean) ||
|
|
!GDALPipeWrite(p, dfStdDev) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ComputeRasterMinMax() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::ComputeRasterMinMax( int bApproxOK,
|
|
double* padfMinMax )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_ComputeRasterMinMax) )
|
|
return GDALPamRasterBand::ComputeRasterMinMax(bApproxOK, padfMinMax);
|
|
|
|
CLIENT_ENTER();
|
|
if( !bApproxOK && CSLTestBoolean(CPLGetConfigOption("GDAL_API_PROXY_FORCE_APPROX", "NO")) )
|
|
bApproxOK = TRUE;
|
|
if( !WriteInstr(INSTR_Band_ComputeRasterMinMax) ||
|
|
!GDALPipeWrite(p, bApproxOK) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet != CE_Failure )
|
|
{
|
|
if( !GDALPipeRead(p, padfMinMax + 0) ||
|
|
!GDALPipeRead(p, padfMinMax + 1) )
|
|
return CE_Failure;
|
|
}
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetHistogram() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::GetHistogram( double dfMin, double dfMax,
|
|
int nBuckets, GUIntBig *panHistogram,
|
|
int bIncludeOutOfRange,
|
|
int bApproxOK,
|
|
GDALProgressFunc pfnProgress,
|
|
void *pProgressData )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetHistogram) )
|
|
return GDALPamRasterBand::GetHistogram(
|
|
dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange, bApproxOK, pfnProgress, pProgressData);
|
|
|
|
CLIENT_ENTER();
|
|
if( !bApproxOK && CSLTestBoolean(CPLGetConfigOption("GDAL_API_PROXY_FORCE_APPROX", "NO")) )
|
|
bApproxOK = TRUE;
|
|
CPLErr eDefaultRet = CE_Failure;
|
|
if( CSLTestBoolean(CPLGetConfigOption("QGIS_HACK", "NO")) )
|
|
{
|
|
memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
|
|
eDefaultRet = CE_None;
|
|
}
|
|
if( !WriteInstr(INSTR_Band_GetHistogram) ||
|
|
!GDALPipeWrite(p, dfMin) ||
|
|
!GDALPipeWrite(p, dfMax) ||
|
|
!GDALPipeWrite(p, nBuckets) ||
|
|
!GDALPipeWrite(p, bIncludeOutOfRange) ||
|
|
!GDALPipeWrite(p, bApproxOK) )
|
|
return eDefaultRet;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return eDefaultRet;
|
|
|
|
CPLErr eRet = eDefaultRet;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet != CE_Failure )
|
|
{
|
|
int nSize;
|
|
if( !GDALPipeRead(p, &nSize) ||
|
|
nSize != nBuckets * (int)sizeof(GUIntBig) ||
|
|
!GDALPipeRead_nolength(p, nSize, panHistogram) )
|
|
return eDefaultRet;
|
|
}
|
|
else if( eDefaultRet == CE_None )
|
|
eRet = eDefaultRet;
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDefaultHistogram() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::GetDefaultHistogram( double *pdfMin,
|
|
double *pdfMax,
|
|
int *pnBuckets,
|
|
GUIntBig ** ppanHistogram,
|
|
int bForce,
|
|
GDALProgressFunc pfnProgress,
|
|
void *pProgressData )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetDefaultHistogram) )
|
|
return GDALPamRasterBand::GetDefaultHistogram(
|
|
pdfMin, pdfMax, pnBuckets, ppanHistogram, bForce, pfnProgress, pProgressData);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetDefaultHistogram) ||
|
|
!GDALPipeWrite(p, bForce) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
if( eRet != CE_Failure )
|
|
{
|
|
double dfMin, dfMax;
|
|
int nBuckets, nSize;
|
|
if( !GDALPipeRead(p, &dfMin) ||
|
|
!GDALPipeRead(p, &dfMax) ||
|
|
!GDALPipeRead(p, &nBuckets) ||
|
|
!GDALPipeRead(p, &nSize) )
|
|
return CE_Failure;
|
|
if( nSize != nBuckets * (int)sizeof(GUIntBig) )
|
|
return CE_Failure;
|
|
if( pdfMin ) *pdfMin = dfMin;
|
|
if( pdfMax ) *pdfMax = dfMax;
|
|
if( pnBuckets ) *pnBuckets = nBuckets;
|
|
if( ppanHistogram )
|
|
{
|
|
*ppanHistogram = (GUIntBig*)VSIMalloc(nSize);
|
|
if( *ppanHistogram == NULL )
|
|
return CE_Failure;
|
|
if( !GDALPipeRead_nolength(p, nSize, *ppanHistogram) )
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
GUIntBig *panHistogram = (GUIntBig*)VSIMalloc(nSize);
|
|
if( panHistogram == NULL )
|
|
return CE_Failure;
|
|
if( !GDALPipeRead_nolength(p, nSize, panHistogram) )
|
|
{
|
|
CPLFree(panHistogram);
|
|
return CE_Failure;
|
|
}
|
|
CPLFree(panHistogram);
|
|
}
|
|
}
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetDefaultHistogram() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
|
|
int nBuckets, GUIntBig *panHistogram )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetDefaultHistogram) )
|
|
return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetDefaultHistogram) ||
|
|
!GDALPipeWrite(p, dfMin) ||
|
|
!GDALPipeWrite(p, dfMax) ||
|
|
!GDALPipeWrite(p, nBuckets) ||
|
|
!GDALPipeWrite(p, nBuckets * sizeof(GUIntBig), panHistogram) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void* pImage)
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_IReadBlock) )
|
|
return CE_Failure;
|
|
|
|
CLIENT_ENTER();
|
|
if( poDS != NULL )
|
|
((GDALClientDataset*)poDS)->ProcessAsyncProgress();
|
|
|
|
if( !WriteInstr(INSTR_Band_IReadBlock) ||
|
|
!GDALPipeWrite(p, nBlockXOff) ||
|
|
!GDALPipeWrite(p, nBlockYOff) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
CPLErr eRet = CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
int nSize;
|
|
if( !GDALPipeRead(p, &nSize) ||
|
|
nSize != nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8) ||
|
|
!GDALPipeRead_nolength(p, nSize, pImage) )
|
|
return CE_Failure;
|
|
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IWriteBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void* pImage)
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_IWriteBlock) )
|
|
return CE_Failure;
|
|
|
|
InvalidateCachedLines();
|
|
|
|
CLIENT_ENTER();
|
|
int nSize = nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8);
|
|
if( !WriteInstr(INSTR_Band_IWriteBlock) ||
|
|
!GDALPipeWrite(p, nBlockXOff) ||
|
|
!GDALPipeWrite(p, nBlockYOff) ||
|
|
!GDALPipeWrite(p, nSize, pImage) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IRasterIO_read_internal() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::IRasterIO_read_internal(
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
GSpacing nPixelSpace, GSpacing nLineSpace)
|
|
{
|
|
CPLErr eRet = CE_Failure;
|
|
|
|
if( !WriteInstr(INSTR_Band_IRasterIO_Read) ||
|
|
!GDALPipeWrite(p, nXOff) ||
|
|
!GDALPipeWrite(p, nYOff) ||
|
|
!GDALPipeWrite(p, nXSize) ||
|
|
!GDALPipeWrite(p, nYSize) ||
|
|
!GDALPipeWrite(p, nBufXSize) ||
|
|
!GDALPipeWrite(p, nBufYSize) ||
|
|
!GDALPipeWrite(p, eBufType) )
|
|
return CE_Failure;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
|
|
int nSize;
|
|
if( !GDALPipeRead(p, &nSize) )
|
|
return CE_Failure;
|
|
int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
|
|
GIntBig nExpectedSize = (GIntBig)nBufXSize * nBufYSize * nDataTypeSize;
|
|
if( nSize != nExpectedSize )
|
|
return CE_Failure;
|
|
if( nPixelSpace == nDataTypeSize &&
|
|
nLineSpace == nBufXSize * nDataTypeSize )
|
|
{
|
|
if( !GDALPipeRead_nolength(p, nSize, pData) )
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
GByte* pBuf = (GByte*)VSIMalloc(nSize);
|
|
if( pBuf == NULL )
|
|
return CE_Failure;
|
|
if( !GDALPipeRead_nolength(p, nSize, pBuf) )
|
|
{
|
|
VSIFree(pBuf);
|
|
return CE_Failure;
|
|
}
|
|
for(int j=0;j<nBufYSize;j++)
|
|
{
|
|
GDALCopyWords( pBuf + j * nBufXSize * nDataTypeSize,
|
|
eBufType, nDataTypeSize,
|
|
(GByte*)pData + j * nLineSpace,
|
|
eBufType, nPixelSpace,
|
|
nBufXSize );
|
|
}
|
|
VSIFree(pBuf);
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* InvalidateCachedLines() */
|
|
/************************************************************************/
|
|
|
|
void GDALClientRasterBand::InvalidateCachedLines()
|
|
{
|
|
nSuccessiveLinesRead = 0;
|
|
nCachedYStart = -1;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IRasterIO() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::IRasterIO( GDALRWFlag eRWFlag,
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
GSpacing nPixelSpace, GSpacing nLineSpace,
|
|
GDALRasterIOExtraArg* psExtraArg )
|
|
{
|
|
if( !SupportsInstr( (eRWFlag == GF_Read) ? INSTR_Band_IRasterIO_Read : INSTR_Band_IRasterIO_Write) )
|
|
return GDALPamRasterBand::IRasterIO( eRWFlag,
|
|
nXOff, nYOff, nXSize, nYSize,
|
|
pData, nBufXSize, nBufYSize,
|
|
eBufType,
|
|
nPixelSpace, nLineSpace, psExtraArg );
|
|
|
|
CLIENT_ENTER();
|
|
CPLErr eRet = CE_Failure;
|
|
|
|
if( poDS != NULL )
|
|
((GDALClientDataset*)poDS)->ProcessAsyncProgress();
|
|
|
|
if( eRWFlag == GF_Read )
|
|
{
|
|
/*if( GetAccess() == GA_Update )
|
|
FlushCache();*/
|
|
|
|
/* Detect scanline reading pattern and read several rows in advance */
|
|
/* to save a few client/server roundtrips */
|
|
if( bEnableLineCaching &&
|
|
nXOff == 0 && nXSize == nRasterXSize && nYSize == 1 &&
|
|
nBufXSize == nXSize && nBufYSize == nYSize )
|
|
{
|
|
int nBufTypeSize = GDALGetDataTypeSize(eBufType) / 8;
|
|
|
|
/* Is the current line already cached ? */
|
|
if( nCachedYStart >= 0 &&
|
|
nYOff >= nCachedYStart && nYOff < nCachedYStart + nCachedLines &&
|
|
eBufType == eCachedBufType )
|
|
{
|
|
nSuccessiveLinesRead ++;
|
|
|
|
int nCachedBufTypeSize = GDALGetDataTypeSize(eCachedBufType) / 8;
|
|
GDALCopyWords(pabyCachedLines + (nYOff - nCachedYStart) * nXSize * nCachedBufTypeSize,
|
|
eCachedBufType, nCachedBufTypeSize,
|
|
pData, eBufType, nPixelSpace,
|
|
nXSize);
|
|
nLastYOff = nYOff;
|
|
eLastBufType = eBufType;
|
|
return CE_None;
|
|
}
|
|
|
|
if( nYOff == nLastYOff + 1 &&
|
|
eBufType == eLastBufType )
|
|
{
|
|
nSuccessiveLinesRead ++;
|
|
if( nSuccessiveLinesRead >= 2 )
|
|
{
|
|
if( pabyCachedLines == NULL )
|
|
{
|
|
nCachedLines = 10 * 1024 * 1024 / (nXSize * nBufTypeSize);
|
|
if( nCachedLines > 1 )
|
|
pabyCachedLines = (GByte*) VSIMalloc(
|
|
nCachedLines * nXSize * nBufTypeSize);
|
|
}
|
|
if( pabyCachedLines != NULL )
|
|
{
|
|
int nLinesToRead = nCachedLines;
|
|
if( nYOff + nLinesToRead > nRasterYSize )
|
|
nLinesToRead = nRasterYSize - nYOff;
|
|
eRet = IRasterIO_read_internal( nXOff, nYOff, nXSize, nLinesToRead,
|
|
pabyCachedLines, nXSize, nLinesToRead,
|
|
eBufType,
|
|
nBufTypeSize, nBufTypeSize * nXSize );
|
|
if( eRet == CE_None )
|
|
{
|
|
eCachedBufType = eBufType;
|
|
nCachedYStart = nYOff;
|
|
|
|
int nCachedBufTypeSize = GDALGetDataTypeSize(eCachedBufType) / 8;
|
|
GDALCopyWords(pabyCachedLines + (nYOff - nCachedYStart) * nXSize * nCachedBufTypeSize,
|
|
eCachedBufType, nCachedBufTypeSize,
|
|
pData, eBufType, nPixelSpace,
|
|
nXSize);
|
|
nLastYOff = nYOff;
|
|
eLastBufType = eBufType;
|
|
|
|
return CE_None;
|
|
}
|
|
else
|
|
InvalidateCachedLines();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
InvalidateCachedLines();
|
|
}
|
|
else
|
|
InvalidateCachedLines();
|
|
|
|
nLastYOff = nYOff;
|
|
eLastBufType = eBufType;
|
|
|
|
return IRasterIO_read_internal( nXOff, nYOff, nXSize, nYSize,
|
|
pData, nBufXSize, nBufYSize,
|
|
eBufType,
|
|
nPixelSpace, nLineSpace );
|
|
}
|
|
else
|
|
{
|
|
InvalidateCachedLines();
|
|
|
|
if( !WriteInstr(INSTR_Band_IRasterIO_Write) ||
|
|
!GDALPipeWrite(p, nXOff) ||
|
|
!GDALPipeWrite(p, nYOff) ||
|
|
!GDALPipeWrite(p, nXSize) ||
|
|
!GDALPipeWrite(p, nYSize) ||
|
|
!GDALPipeWrite(p, nBufXSize) ||
|
|
!GDALPipeWrite(p, nBufYSize) ||
|
|
!GDALPipeWrite(p, eBufType) )
|
|
return CE_Failure;
|
|
|
|
int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
|
|
GIntBig nSizeBig = (GIntBig)nBufXSize * nBufYSize * nDataTypeSize;
|
|
int nSize = (int)nSizeBig;
|
|
if( nSizeBig != nSize )
|
|
return CE_Failure;
|
|
if( nPixelSpace == nDataTypeSize &&
|
|
nLineSpace == nBufXSize * nDataTypeSize )
|
|
{
|
|
if( !GDALPipeWrite(p, nSize, pData) )
|
|
return CE_Failure;
|
|
}
|
|
else
|
|
{
|
|
GByte* pBuf = (GByte*)VSIMalloc(nSize);
|
|
if( pBuf == NULL )
|
|
return CE_Failure;
|
|
for(int j=0;j<nBufYSize;j++)
|
|
{
|
|
GDALCopyWords( (GByte*)pData + j * nLineSpace,
|
|
eBufType, nPixelSpace,
|
|
pBuf + j * nBufXSize * nDataTypeSize,
|
|
eBufType, nDataTypeSize,
|
|
nBufXSize );
|
|
}
|
|
if( !GDALPipeWrite(p, nSize, pBuf) )
|
|
{
|
|
VSIFree(pBuf);
|
|
return CE_Failure;
|
|
}
|
|
VSIFree(pBuf);
|
|
}
|
|
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CE_Failure;
|
|
if( !GDALPipeRead(p, &eRet) )
|
|
return eRet;
|
|
|
|
GDALConsumeErrors(p);
|
|
return eRet;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* HasArbitraryOverviews() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientRasterBand::HasArbitraryOverviews()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_HasArbitraryOverviews) )
|
|
return GDALPamRasterBand::HasArbitraryOverviews();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_HasArbitraryOverviews) )
|
|
return 0;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return 0;
|
|
|
|
int nInt;
|
|
if( !GDALPipeRead(p, &nInt) )
|
|
return 0;
|
|
GDALConsumeErrors(p);
|
|
return nInt;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverviewCount() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientRasterBand::GetOverviewCount()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetOverviewCount) )
|
|
return GDALPamRasterBand::GetOverviewCount();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetOverviewCount) )
|
|
return 0;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return 0;
|
|
|
|
int nInt;
|
|
if( !GDALPipeRead(p, &nInt) )
|
|
return 0;
|
|
GDALConsumeErrors(p);
|
|
return nInt;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDouble() */
|
|
/************************************************************************/
|
|
|
|
double GDALClientRasterBand::GetDouble( InstrEnum instr, int *pbSuccess )
|
|
{
|
|
if( pbSuccess ) *pbSuccess = FALSE;
|
|
if( !WriteInstr( instr) )
|
|
return 0;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return 0;
|
|
|
|
int bSuccess;
|
|
double dfRet;
|
|
if( !GDALPipeRead(p, &bSuccess) ||
|
|
!GDALPipeRead(p, &dfRet) )
|
|
return 0;
|
|
if( pbSuccess )
|
|
*pbSuccess = bSuccess;
|
|
GDALConsumeErrors(p);
|
|
return dfRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetNoDataValue() */
|
|
/************************************************************************/
|
|
|
|
double GDALClientRasterBand::GetNoDataValue( int *pbSuccess )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetNoDataValue) )
|
|
return GDALPamRasterBand::GetNoDataValue(pbSuccess);
|
|
|
|
CLIENT_ENTER();
|
|
return GetDouble(INSTR_Band_GetNoDataValue, pbSuccess);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaximum() */
|
|
/************************************************************************/
|
|
|
|
double GDALClientRasterBand::GetMaximum( int *pbSuccess )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetMaximum) )
|
|
return GDALPamRasterBand::GetMaximum(pbSuccess);
|
|
|
|
CLIENT_ENTER();
|
|
return GetDouble(INSTR_Band_GetMaximum, pbSuccess);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMinimum() */
|
|
/************************************************************************/
|
|
|
|
double GDALClientRasterBand::GetMinimum( int *pbSuccess )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetMinimum) )
|
|
return GDALPamRasterBand::GetMinimum(pbSuccess);
|
|
|
|
CLIENT_ENTER();
|
|
return GetDouble(INSTR_Band_GetMinimum, pbSuccess);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOffset() */
|
|
/************************************************************************/
|
|
|
|
double GDALClientRasterBand::GetOffset( int *pbSuccess )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetOffset) )
|
|
return GDALPamRasterBand::GetOffset(pbSuccess);
|
|
|
|
CLIENT_ENTER();
|
|
return GetDouble(INSTR_Band_GetOffset, pbSuccess);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetScale() */
|
|
/************************************************************************/
|
|
|
|
double GDALClientRasterBand::GetScale( int *pbSuccess )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetScale) )
|
|
return GDALPamRasterBand::GetScale(pbSuccess);
|
|
|
|
CLIENT_ENTER();
|
|
return GetDouble(INSTR_Band_GetScale, pbSuccess);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorTable() */
|
|
/************************************************************************/
|
|
|
|
GDALColorTable *GDALClientRasterBand::GetColorTable()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetColorTable) )
|
|
return GDALPamRasterBand::GetColorTable();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetColorTable) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
GDALColorTable* poNewColorTable = NULL;
|
|
if( !GDALPipeRead(p, &poNewColorTable) )
|
|
return NULL;
|
|
|
|
if( poNewColorTable != NULL && poColorTable != NULL )
|
|
{
|
|
*poColorTable = *poNewColorTable;
|
|
delete poNewColorTable;
|
|
}
|
|
else if( poNewColorTable != NULL && poColorTable == NULL )
|
|
{
|
|
poColorTable = poNewColorTable;
|
|
}
|
|
else if( poColorTable != NULL )
|
|
{
|
|
delete poColorTable;
|
|
poColorTable = NULL;
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
return poColorTable;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetUnitType() */
|
|
/************************************************************************/
|
|
|
|
const char *GDALClientRasterBand::GetUnitType()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetUnitType) )
|
|
return GDALPamRasterBand::GetUnitType();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetUnitType) )
|
|
return "";
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return "";
|
|
|
|
CPLFree(pszUnitType);
|
|
pszUnitType = NULL;
|
|
if( !GDALPipeRead(p, &pszUnitType) )
|
|
return "";
|
|
GDALConsumeErrors(p);
|
|
return pszUnitType ? pszUnitType : "";
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetUnitType() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetUnitType( const char * pszUnit )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetUnitType) )
|
|
return GDALPamRasterBand::SetUnitType(pszUnit);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetUnitType) ||
|
|
!GDALPipeWrite(p, pszUnit) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
/************************************************************************/
|
|
/* SetColorTable() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetColorTable(GDALColorTable* poColorTable)
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetColorTable) )
|
|
return GDALPamRasterBand::SetColorTable(poColorTable);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetColorTable) )
|
|
return CE_Failure;
|
|
if( !GDALPipeWrite(p, poColorTable) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetDouble() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetDouble( InstrEnum instr, double dfVal )
|
|
{
|
|
if( !WriteInstr(instr) ||
|
|
!GDALPipeWrite(p, dfVal) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetNoDataValue() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetNoDataValue( double dfVal )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetNoDataValue) )
|
|
return GDALPamRasterBand::SetNoDataValue(dfVal);
|
|
|
|
CLIENT_ENTER();
|
|
return SetDouble(INSTR_Band_SetNoDataValue, dfVal);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetScale() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetScale( double dfVal )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetScale) )
|
|
return GDALPamRasterBand::SetScale(dfVal);
|
|
|
|
CLIENT_ENTER();
|
|
return SetDouble(INSTR_Band_SetScale, dfVal);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetOffset() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetOffset( double dfVal )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetOffset) )
|
|
return GDALPamRasterBand::SetOffset(dfVal);
|
|
|
|
CLIENT_ENTER();
|
|
return SetDouble(INSTR_Band_SetOffset, dfVal);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOverview() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *GDALClientRasterBand::GetOverview(int iOverview)
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetOverview) )
|
|
return GDALPamRasterBand::GetOverview(iOverview);
|
|
|
|
CLIENT_ENTER();
|
|
std::map<int, GDALRasterBand*>::iterator oIter =
|
|
aMapOvrBandsCurrent.find(iOverview);
|
|
if( oIter != aMapOvrBandsCurrent.end() )
|
|
return oIter->second;
|
|
|
|
if( !WriteInstr(INSTR_Band_GetOverview) ||
|
|
!GDALPipeWrite(p, iOverview) )
|
|
return NULL;
|
|
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
GDALRasterBand* poBand = NULL;
|
|
if( !GDALPipeRead(p, (GDALClientDataset*) NULL, &poBand, abyCaps) )
|
|
return NULL;
|
|
|
|
GDALConsumeErrors(p);
|
|
|
|
aMapOvrBands[iOverview] = poBand;
|
|
aMapOvrBandsCurrent[iOverview] = poBand;
|
|
return poBand;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaskBand() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBand *GDALClientRasterBand::GetMaskBand()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetMaskBand) )
|
|
return GDALPamRasterBand::GetMaskBand();
|
|
|
|
CLIENT_ENTER();
|
|
if( poMaskBand )
|
|
return poMaskBand;
|
|
|
|
if( !WriteInstr(INSTR_Band_GetMaskBand) )
|
|
return CreateFakeMaskBand();
|
|
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return CreateFakeMaskBand();
|
|
|
|
GDALRasterBand* poBand = NULL;
|
|
if( !GDALPipeRead(p, (GDALClientDataset*) NULL, &poBand, abyCaps) )
|
|
return CreateFakeMaskBand();
|
|
|
|
GDALConsumeErrors(p);
|
|
|
|
poMaskBand = poBand;
|
|
return poMaskBand;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMaskFlags() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientRasterBand::GetMaskFlags()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetMaskFlags) )
|
|
return GDALPamRasterBand::GetMaskFlags();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetMaskFlags) )
|
|
return 0;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return 0;
|
|
int nFlags;
|
|
if( !GDALPipeRead(p, &nFlags) )
|
|
return 0;
|
|
GDALConsumeErrors(p);
|
|
return nFlags;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateMaskBand() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::CreateMaskBand( int nFlags )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_CreateMaskBand) )
|
|
return GDALPamRasterBand::CreateMaskBand(nFlags);
|
|
|
|
CLIENT_ENTER();
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_INTERNAL_MASK", bRecycleChild);
|
|
if( !WriteInstr(INSTR_Band_CreateMaskBand) ||
|
|
!GDALPipeWrite(p, nFlags) )
|
|
return CE_Failure;
|
|
CPLErr eErr = CPLErrOnlyRet(p);
|
|
if( eErr == CE_None && poMaskBand != NULL )
|
|
{
|
|
apoOldMaskBands.push_back(poMaskBand);
|
|
poMaskBand = NULL;
|
|
}
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Fill() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_Fill) )
|
|
return GDALPamRasterBand::Fill(dfRealValue, dfImaginaryValue);
|
|
|
|
InvalidateCachedLines();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_Fill) ||
|
|
!GDALPipeWrite(p, dfRealValue) ||
|
|
!GDALPipeWrite(p, dfImaginaryValue) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildOverviews() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::BuildOverviews( const char * pszResampling,
|
|
int nOverviews,
|
|
int * panOverviewList,
|
|
GDALProgressFunc pfnProgress,
|
|
void * pProgressData )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_BuildOverviews) )
|
|
return GDALPamRasterBand::BuildOverviews(pszResampling, nOverviews, panOverviewList,
|
|
pfnProgress, pProgressData);
|
|
|
|
InvalidateCachedLines();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_BuildOverviews) ||
|
|
!GDALPipeWrite(p, pszResampling) ||
|
|
!GDALPipeWrite(p, nOverviews) ||
|
|
!GDALPipeWrite(p, nOverviews * sizeof(int), panOverviewList) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDefaultRAT() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterAttributeTable *GDALClientRasterBand::GetDefaultRAT()
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_GetDefaultRAT) )
|
|
return GDALPamRasterBand::GetDefaultRAT();
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_GetDefaultRAT) )
|
|
return NULL;
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return NULL;
|
|
|
|
GDALRasterAttributeTable* poNewRAT = NULL;
|
|
if( !GDALPipeRead(p, &poNewRAT) )
|
|
return NULL;
|
|
|
|
if( poNewRAT != NULL && poRAT != NULL )
|
|
{
|
|
*poRAT = *poNewRAT;
|
|
delete poNewRAT;
|
|
}
|
|
else if( poNewRAT != NULL && poRAT == NULL )
|
|
{
|
|
poRAT = poNewRAT;
|
|
}
|
|
else if( poRAT != NULL )
|
|
{
|
|
delete poRAT;
|
|
poRAT = NULL;
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
return poRAT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetDefaultRAT() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::SetDefaultRAT( const GDALRasterAttributeTable * poRAT )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_SetDefaultRAT) )
|
|
return GDALPamRasterBand::SetDefaultRAT(poRAT);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_SetDefaultRAT) ||
|
|
!GDALPipeWrite(p, poRAT) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AdviseRead() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
|
|
int nBufXSize, int nBufYSize,
|
|
GDALDataType eDT, char **papszOptions )
|
|
{
|
|
if( !SupportsInstr(INSTR_Band_AdviseRead) )
|
|
return GDALPamRasterBand::AdviseRead(nXOff, nYOff, nXSize, nYSize,
|
|
nBufXSize, nBufYSize,
|
|
eDT, papszOptions);
|
|
|
|
CLIENT_ENTER();
|
|
if( !WriteInstr(INSTR_Band_AdviseRead) ||
|
|
!GDALPipeWrite(p, nXOff) ||
|
|
!GDALPipeWrite(p, nYOff) ||
|
|
!GDALPipeWrite(p, nXSize) ||
|
|
!GDALPipeWrite(p, nYSize) ||
|
|
!GDALPipeWrite(p, nBufXSize) ||
|
|
!GDALPipeWrite(p, nBufYSize) ||
|
|
!GDALPipeWrite(p, eDT) ||
|
|
!GDALPipeWrite(p, papszOptions) )
|
|
return CE_Failure;
|
|
return CPLErrOnlyRet(p);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateAndConnect() */
|
|
/************************************************************************/
|
|
|
|
GDALClientDataset* GDALClientDataset::CreateAndConnect()
|
|
{
|
|
GDALServerSpawnedProcess* ssp = GDALServerSpawnAsync();
|
|
if( ssp == NULL )
|
|
return NULL;
|
|
return new GDALClientDataset(ssp);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Init() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientDataset::Init(const char* pszFilename, GDALAccess eAccess)
|
|
{
|
|
// FIXME find a way of transmitting the relevant config options to the forked Open() ?
|
|
GDALPipeWriteConfigOption(p, "GTIFF_POINT_GEO_IGNORE", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_OVR_BLOCKSIZE", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GTIFF_LINEAR_UNITS", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GTIFF_IGNORE_READ_ERRORS", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_RENDERING_OPTIONS", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_DPI", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_LIB", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_LAYERS", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_LAYERS_OFF", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_JPEG_TO_RGB", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "RPFTOC_FORCE_RGBA", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_NETCDF_BOTTOMUP", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "OGR_SQLITE_SYNCHRONOUS", bRecycleChild);
|
|
|
|
char* pszCWD = CPLGetCurrentDir();
|
|
|
|
if( !GDALPipeWrite(p, INSTR_Open) ||
|
|
!GDALPipeWrite(p, eAccess) ||
|
|
!GDALPipeWrite(p, pszFilename) ||
|
|
!GDALPipeWrite(p, pszCWD))
|
|
{
|
|
CPLFree(pszCWD);
|
|
return FALSE;
|
|
}
|
|
CPLFree(pszCWD);
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return FALSE;
|
|
int bRet = FALSE;
|
|
if( !GDALPipeRead(p, &bRet) )
|
|
return FALSE;
|
|
|
|
if( bRet == FALSE )
|
|
{
|
|
GDALConsumeErrors(p);
|
|
return FALSE;
|
|
}
|
|
|
|
if( !GDALPipeRead(p, sizeof(abyCaps), abyCaps) )
|
|
return FALSE;
|
|
|
|
this->eAccess = eAccess;
|
|
|
|
char* pszDescription = NULL;
|
|
if( !GDALPipeRead(p, &pszDescription) )
|
|
return FALSE;
|
|
if( pszDescription != NULL )
|
|
SetDescription(pszDescription);
|
|
CPLFree(pszDescription);
|
|
|
|
char* pszDriverName = NULL;
|
|
if( !GDALPipeRead(p, &pszDriverName) )
|
|
return FALSE;
|
|
|
|
if( pszDriverName != NULL )
|
|
{
|
|
bFreeDriver = TRUE;
|
|
poDriver = new GDALDriver();
|
|
poDriver->SetDescription(pszDriverName);
|
|
CPLFree(pszDriverName);
|
|
pszDriverName = NULL;
|
|
|
|
while(TRUE)
|
|
{
|
|
char* pszKey = NULL, *pszVal = NULL;
|
|
if( !GDALPipeRead(p, &pszKey) )
|
|
return FALSE;
|
|
if( pszKey == NULL )
|
|
break;
|
|
if( !GDALPipeRead(p, &pszVal) )
|
|
{
|
|
CPLFree(pszKey);
|
|
CPLFree(pszVal);
|
|
return FALSE;
|
|
}
|
|
poDriver->SetMetadataItem( pszKey, pszVal );
|
|
CPLFree(pszKey);
|
|
CPLFree(pszVal);
|
|
}
|
|
}
|
|
CPLFree(pszDriverName);
|
|
|
|
int bAllSame;
|
|
if( !GDALPipeRead(p, &nRasterXSize) ||
|
|
!GDALPipeRead(p, &nRasterYSize) ||
|
|
!GDALPipeRead(p, &nBands) ||
|
|
!GDALPipeRead(p, &bAllSame) )
|
|
return FALSE;
|
|
|
|
for(int i=0;i<nBands;i++)
|
|
{
|
|
GDALRasterBand* poBand = NULL;
|
|
if( i > 0 && bAllSame )
|
|
{
|
|
GDALClientRasterBand* poFirstBand = (GDALClientRasterBand*) GetRasterBand(1);
|
|
int nBlockXSize, nBlockYSize;
|
|
poFirstBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
|
|
poBand = new GDALClientRasterBand(p, poFirstBand->GetSrvBand() + i,
|
|
this, i + 1, poFirstBand->GetAccess(),
|
|
poFirstBand->GetXSize(),
|
|
poFirstBand->GetYSize(),
|
|
poFirstBand->GetRasterDataType(),
|
|
nBlockXSize, nBlockYSize,
|
|
abyCaps);
|
|
}
|
|
else
|
|
{
|
|
if( !GDALPipeRead(p, this, &poBand, abyCaps) )
|
|
return FALSE;
|
|
if( poBand == NULL )
|
|
return FALSE;
|
|
}
|
|
|
|
SetBand(i+1, poBand);
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALClientDatasetGetFilename() */
|
|
/************************************************************************/
|
|
|
|
static int IsSeparateExecutable()
|
|
{
|
|
#ifdef WIN32
|
|
return TRUE;
|
|
#else
|
|
const char* pszSpawnServer = CPLGetConfigOption("GDAL_API_PROXY_SERVER", "NO");
|
|
if( EQUAL(pszSpawnServer, "NO") || EQUAL(pszSpawnServer, "OFF") ||
|
|
EQUAL(pszSpawnServer, "FALSE") || EQUAL(pszSpawnServer, "0") )
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
const char* GDALClientDatasetGetFilename(const char* pszFilename)
|
|
{
|
|
const char* pszSpawn;
|
|
if( EQUALN(pszFilename, "API_PROXY:", strlen("API_PROXY:")) )
|
|
{
|
|
pszFilename += strlen("API_PROXY:");
|
|
pszSpawn = "YES";
|
|
}
|
|
else
|
|
{
|
|
pszSpawn = CPLGetConfigOption("GDAL_API_PROXY", "NO");
|
|
if( EQUAL(pszSpawn, "NO") || EQUAL(pszSpawn, "OFF") ||
|
|
EQUAL(pszSpawn, "FALSE") || EQUAL(pszSpawn, "0") )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Those datasets cannot work in a multi-process context */
|
|
/* /vsistdin/ and /vsistdout/ can work on Unix in the fork() only context (i.e. GDAL_API_PROXY_SERVER undefined) */
|
|
/* since the forked process will inherit the same descriptors as the parent */
|
|
|
|
if( EQUALN(pszFilename, "MEM:::", 6) ||
|
|
strstr(pszFilename, "/vsimem/") != NULL ||
|
|
strstr(pszFilename, "/vsimem\\") != NULL ||
|
|
(strstr(pszFilename, "/vsistdout/") != NULL && IsSeparateExecutable()) ||
|
|
(strstr(pszFilename, "/vsistdin/") != NULL && IsSeparateExecutable()) ||
|
|
EQUALN(pszFilename,"NUMPY:::",8) )
|
|
return NULL;
|
|
|
|
if( !(EQUAL(pszSpawn, "YES") || EQUAL(pszSpawn, "ON") ||
|
|
EQUAL(pszSpawn, "TRUE") || EQUAL(pszSpawn, "1")) )
|
|
{
|
|
CPLString osExt(CPLGetExtension(pszFilename));
|
|
|
|
/* If the file extension is listed in the GDAL_API_PROXY, then */
|
|
/* we have a match */
|
|
char** papszTokens = CSLTokenizeString2( pszSpawn, " ,", CSLT_HONOURSTRINGS );
|
|
if( CSLFindString(papszTokens, osExt) >= 0 )
|
|
{
|
|
CSLDestroy(papszTokens);
|
|
return pszFilename;
|
|
}
|
|
|
|
/* Otherwise let's suppose that driver names are listed in GDAL_API_PROXY */
|
|
/* and check if the file extension matches the extension declared by the */
|
|
/* driver */
|
|
char** papszIter = papszTokens;
|
|
while( *papszIter != NULL )
|
|
{
|
|
GDALDriverH hDriver = GDALGetDriverByName(*papszIter);
|
|
if( hDriver != NULL )
|
|
{
|
|
const char* pszDriverExt =
|
|
GDALGetMetadataItem(hDriver, GDAL_DMD_EXTENSION, NULL);
|
|
if( pszDriverExt != NULL && EQUAL(pszDriverExt, osExt) )
|
|
{
|
|
CSLDestroy(papszTokens);
|
|
return pszFilename;
|
|
}
|
|
}
|
|
papszIter++;
|
|
}
|
|
CSLDestroy(papszTokens);
|
|
return NULL;
|
|
}
|
|
|
|
return pszFilename;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *GDALClientDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
{
|
|
const char* pszFilename =
|
|
GDALClientDatasetGetFilename(poOpenInfo->pszFilename);
|
|
if( pszFilename == NULL )
|
|
return NULL;
|
|
|
|
CLIENT_ENTER();
|
|
|
|
GDALClientDataset* poDS = CreateAndConnect();
|
|
if( poDS == NULL )
|
|
return NULL;
|
|
|
|
CPLErrorReset();
|
|
if( !poDS->Init(pszFilename, poOpenInfo->eAccess) )
|
|
{
|
|
if( CPLGetLastErrorType() == 0 )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Could not open %s",
|
|
pszFilename);
|
|
}
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
if( poDS != NULL )
|
|
CPLErrorReset();
|
|
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Identify() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientDataset::Identify( GDALOpenInfo * poOpenInfo )
|
|
{
|
|
const char* pszFilename =
|
|
GDALClientDatasetGetFilename(poOpenInfo->pszFilename);
|
|
if( pszFilename == NULL )
|
|
return FALSE;
|
|
|
|
CLIENT_ENTER();
|
|
|
|
GDALServerSpawnedProcess* ssp = GDALServerSpawnAsync();
|
|
if( ssp == NULL )
|
|
return FALSE;
|
|
|
|
char* pszCWD = CPLGetCurrentDir();
|
|
|
|
GDALPipe* p = ssp->p;
|
|
if( !GDALPipeWrite(p, INSTR_Identify) ||
|
|
!GDALPipeWrite(p, pszFilename) ||
|
|
!GDALPipeWrite(p, pszCWD) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p) )
|
|
{
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
CPLFree(pszCWD);
|
|
return FALSE;
|
|
}
|
|
|
|
CPLFree(pszCWD);
|
|
|
|
int bRet;
|
|
if( !GDALPipeRead(p, &bRet) )
|
|
{
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return FALSE;
|
|
}
|
|
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return bRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALClientDatasetQuietDelete() */
|
|
/************************************************************************/
|
|
|
|
static int GDALClientDatasetQuietDelete(GDALPipe* p,
|
|
const char* pszFilename)
|
|
{
|
|
char* pszCWD = CPLGetCurrentDir();
|
|
if( !GDALPipeWrite(p, INSTR_QuietDelete) ||
|
|
!GDALPipeWrite(p, pszFilename) ||
|
|
!GDALPipeWrite(p, pszCWD) ||
|
|
!GDALSkipUntilEndOfJunkMarker(p) )
|
|
{
|
|
CPLFree(pszCWD);
|
|
return FALSE;
|
|
}
|
|
CPLFree(pszCWD);
|
|
GDALConsumeErrors(p);
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* mCreateCopy() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientDataset::mCreateCopy( const char* pszFilename,
|
|
GDALDataset* poSrcDS,
|
|
int bStrict, char** papszOptions,
|
|
GDALProgressFunc pfnProgress,
|
|
void * pProgressData )
|
|
{
|
|
/*if( !SupportsInstr(INSTR_CreateCopy) )
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported, "CreateCopy() not supported by server");
|
|
return FALSE;
|
|
}*/
|
|
|
|
const char* pszServerDriver =
|
|
CSLFetchNameValue(papszOptions, "SERVER_DRIVER");
|
|
if( pszServerDriver == NULL )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Creation options should contain a SERVER_DRIVER item");
|
|
return FALSE;
|
|
}
|
|
|
|
if( !CSLFetchBoolean(papszOptions, "APPEND_SUBDATASET", FALSE) )
|
|
{
|
|
if( !GDALClientDatasetQuietDelete(p, pszFilename) )
|
|
return FALSE;
|
|
}
|
|
|
|
GDALPipeWriteConfigOption(p, "GTIFF_POINT_GEO_IGNORE", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GTIFF_DELETE_ON_ERROR", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "ESRI_XML_PAM", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "OGR_SQLITE_SYNCHRONOUS", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_WRITE_GEOREF_ON_IMAGE", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p, "GDAL_PDF_OGC_BP_WRITE_WKT", bRecycleChild);
|
|
|
|
char* pszCWD = CPLGetCurrentDir();
|
|
|
|
if( !GDALPipeWrite(p, INSTR_CreateCopy) ||
|
|
!GDALPipeWrite(p, pszFilename) ||
|
|
!GDALPipeWrite(p, poSrcDS->GetDescription()) ||
|
|
!GDALPipeWrite(p, pszCWD) ||
|
|
!GDALPipeWrite(p, bStrict) ||
|
|
!GDALPipeWrite(p, papszOptions) )
|
|
{
|
|
CPLFree(pszCWD);
|
|
return FALSE;
|
|
}
|
|
CPLFree(pszCWD);
|
|
|
|
int bDriverOK;
|
|
if( !GDALPipeRead(p, &bDriverOK) )
|
|
return FALSE;
|
|
|
|
if( !bDriverOK )
|
|
{
|
|
GDALConsumeErrors(p);
|
|
return FALSE;
|
|
}
|
|
|
|
if( GDALServerLoop(p,
|
|
poSrcDS,
|
|
pfnProgress, pProgressData) != 0 )
|
|
{
|
|
GDALConsumeErrors(p);
|
|
return FALSE;
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
|
|
return Init(NULL, GA_Update);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CreateCopy() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *GDALClientDataset::CreateCopy( const char * pszFilename,
|
|
GDALDataset * poSrcDS, int bStrict,
|
|
char ** papszOptions,
|
|
GDALProgressFunc pfnProgress,
|
|
void * pProgressData )
|
|
{
|
|
CLIENT_ENTER();
|
|
|
|
GDALClientDataset* poDS = CreateAndConnect();
|
|
if( poDS !=NULL && !poDS->mCreateCopy(pszFilename, poSrcDS, bStrict,
|
|
papszOptions,
|
|
pfnProgress, pProgressData) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* mCreate() */
|
|
/************************************************************************/
|
|
|
|
int GDALClientDataset::mCreate( const char * pszFilename,
|
|
int nXSize, int nYSize, int nBands,
|
|
GDALDataType eType,
|
|
char ** papszOptions )
|
|
{
|
|
/*if( !SupportsInstr(INSTR_Create) )
|
|
{
|
|
CPLError(CE_Failure, CPLE_NotSupported, "Create() not supported by server");
|
|
return FALSE;
|
|
}*/
|
|
|
|
const char* pszServerDriver =
|
|
CSLFetchNameValue(papszOptions, "SERVER_DRIVER");
|
|
if( pszServerDriver == NULL )
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"Creation options should contain a SERVER_DRIVER item");
|
|
return FALSE;
|
|
}
|
|
|
|
if( !CSLFetchBoolean(papszOptions, "APPEND_SUBDATASET", FALSE) )
|
|
{
|
|
if( !GDALClientDatasetQuietDelete(p, pszFilename) )
|
|
return FALSE;
|
|
}
|
|
|
|
GDALPipeWriteConfigOption(p,"GTIFF_POINT_GEO_IGNORE", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p,"GTIFF_DELETE_ON_ERROR", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p,"ESRI_XML_PAM", bRecycleChild);
|
|
GDALPipeWriteConfigOption(p,"GTIFF_DONT_WRITE_BLOCKS", bRecycleChild);
|
|
|
|
char* pszCWD = CPLGetCurrentDir();
|
|
|
|
if( !GDALPipeWrite(p, INSTR_Create) ||
|
|
!GDALPipeWrite(p, pszFilename) ||
|
|
!GDALPipeWrite(p, pszCWD) ||
|
|
!GDALPipeWrite(p, nXSize) ||
|
|
!GDALPipeWrite(p, nYSize) ||
|
|
!GDALPipeWrite(p, nBands) ||
|
|
!GDALPipeWrite(p, eType) ||
|
|
!GDALPipeWrite(p, papszOptions) )
|
|
{
|
|
CPLFree(pszCWD);
|
|
return FALSE;
|
|
}
|
|
CPLFree(pszCWD);
|
|
if( !GDALSkipUntilEndOfJunkMarker(p) )
|
|
return FALSE;
|
|
int bOK;
|
|
if( !GDALPipeRead(p, &bOK) )
|
|
return FALSE;
|
|
|
|
if( !bOK )
|
|
{
|
|
GDALConsumeErrors(p);
|
|
return FALSE;
|
|
}
|
|
|
|
GDALConsumeErrors(p);
|
|
|
|
return Init(NULL, GA_Update);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Create() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset* GDALClientDataset::Create( const char * pszName,
|
|
int nXSize, int nYSize, int nBands,
|
|
GDALDataType eType,
|
|
char ** papszOptions )
|
|
{
|
|
CLIENT_ENTER();
|
|
|
|
GDALClientDataset* poDS = CreateAndConnect();
|
|
if( poDS != NULL && !poDS->mCreate(pszName, nXSize, nYSize, nBands,
|
|
eType, papszOptions) )
|
|
{
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Delete() */
|
|
/************************************************************************/
|
|
|
|
CPLErr GDALClientDataset::Delete( const char * pszFilename )
|
|
{
|
|
pszFilename =
|
|
GDALClientDatasetGetFilename(pszFilename);
|
|
if( pszFilename == NULL )
|
|
return CE_Failure;
|
|
|
|
CLIENT_ENTER();
|
|
|
|
GDALServerSpawnedProcess* ssp = GDALServerSpawnAsync();
|
|
if( ssp == NULL )
|
|
return CE_Failure;
|
|
|
|
GDALPipe* p = ssp->p;
|
|
if( !GDALClientDatasetQuietDelete(p, pszFilename) )
|
|
{
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return CE_Failure;
|
|
}
|
|
|
|
GDALServerSpawnAsyncFinish(ssp);
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALUnloadAPIPROXYDriver() */
|
|
/************************************************************************/
|
|
static GDALDriver* poAPIPROXYDriver = NULL;
|
|
|
|
static void GDALUnloadAPIPROXYDriver(CPL_UNUSED GDALDriver* poDriver)
|
|
{
|
|
if( bRecycleChild )
|
|
{
|
|
/* Kill all unused descriptors */
|
|
bRecycleChild = FALSE;
|
|
for(int i=0;i<nMaxRecycled;i++)
|
|
{
|
|
if( aspRecycled[i] != NULL )
|
|
{
|
|
GDALServerSpawnAsyncFinish(aspRecycled[i]);
|
|
aspRecycled[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
poAPIPROXYDriver = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALGetAPIPROXYDriver() */
|
|
/************************************************************************/
|
|
|
|
GDALDriver* GDALGetAPIPROXYDriver()
|
|
{
|
|
CPLMutexHolderD(GDALGetphDMMutex());
|
|
if( poAPIPROXYDriver == NULL )
|
|
{
|
|
#ifdef DEBUG
|
|
CPLAssert(INSTR_END + 1 == sizeof(apszInstr) / sizeof(apszInstr[0]));
|
|
#endif
|
|
/* If asserted, change GDAL_CLIENT_SERVER_PROTOCOL_MAJOR / GDAL_CLIENT_SERVER_PROTOCOL_MINOR */
|
|
CPLAssert(INSTR_END + 1 == 80);
|
|
|
|
const char* pszConnPool = CPLGetConfigOption("GDAL_API_PROXY_CONN_POOL", "YES");
|
|
if( atoi(pszConnPool) > 0 )
|
|
{
|
|
bRecycleChild = TRUE;
|
|
nMaxRecycled = MIN(atoi(pszConnPool), MAX_RECYCLED);
|
|
}
|
|
else if( CSLTestBoolean(pszConnPool) )
|
|
{
|
|
bRecycleChild = TRUE;
|
|
nMaxRecycled = DEFAULT_RECYCLED;
|
|
}
|
|
memset(aspRecycled, 0, sizeof(aspRecycled));
|
|
|
|
poAPIPROXYDriver = new GDALDriver();
|
|
|
|
poAPIPROXYDriver->SetDescription( "API_PROXY" );
|
|
poAPIPROXYDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poAPIPROXYDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"API_PROXY" );
|
|
|
|
poAPIPROXYDriver->pfnOpen = GDALClientDataset::Open;
|
|
poAPIPROXYDriver->pfnIdentify = GDALClientDataset::Identify;
|
|
poAPIPROXYDriver->pfnCreateCopy = GDALClientDataset::CreateCopy;
|
|
poAPIPROXYDriver->pfnCreate = GDALClientDataset::Create;
|
|
poAPIPROXYDriver->pfnDelete = GDALClientDataset::Delete;
|
|
poAPIPROXYDriver->pfnUnloadDriver = GDALUnloadAPIPROXYDriver;
|
|
}
|
|
return poAPIPROXYDriver;
|
|
}
|