text: /******************************************************************************
   * $Id$
   *
   * Project:  MapServer
   * Purpose:  Interface file for MapServer PHP scripting extension
   *           called MapScript. This file was originally based on
   *           the SWIG interface file mapscript.i
   * Author:   Daniel Morissette, DM Solutions Group (dmorissette@dmsolutions.ca)
   *
   **********************************************************************
   * Copyright (c) 2000, 2007, Daniel Morissette, DM Solutions Group Inc.
   *
   * 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 of this Software or works derived from this 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 "php_mapscript.h"
  
  /* grab mapserver declarations to wrap
   */
  #include "../../mapserver.h"
  #include "../../maperror.h"
  #include "../../mapprimitive.h"
  #include "../../mapsymbol.h"
  #include "../../mapshape.h"
  #include "../../mapproject.h"
  #include "../../maphash.h"
  
  /**********************************************************************
   * class extensions for mapObj
   **********************************************************************/
  mapObj *mapObj_new(char *filename, char *new_path)
  {
    if(filename && strlen(filename))
      return msLoadMap(filename, new_path);
    else { /* create an empty map, no layers etc... */
      return msNewMapObj();
    }
  }
  
  mapObj *mapObj_newFromString(char *map_text, char *new_path)
  {
  
    if(map_text && strlen(map_text))
      return msLoadMapFromString(map_text, new_path);
    else { /* create an empty map, no layers etc... */
      return msNewMapObj();
    }
  }
  
  void  mapObj_destroy(mapObj* self)
  {
    msFreeMap(self);
  }
  
  mapObj *mapObj_clone(mapObj* self)
  {
    mapObj *dstMap;
    dstMap = msNewMapObj();
    if (msCopyMap(dstMap, self) != MS_SUCCESS) {
      msFreeMap(dstMap);
      dstMap = NULL;
    }
    return dstMap;
  }
  
  int mapObj_setRotation(mapObj* self, double rotation_angle )
  {
    return msMapSetRotation( self, rotation_angle );
  }
  
  layerObj *mapObj_getLayer(mapObj* self, int i)
  {
    if(i >= 0 && i < self->numlayers)
      return (self->layers[i]); /* returns an EXISTING layer */
    else
      return NULL;
  }
  
  layerObj *mapObj_getLayerByName(mapObj* self, char *name)
  {
    int i;
  
    i = msGetLayerIndex(self, name);
  
    if(i != -1)
      return (self->layers[i]); /* returns an EXISTING layer */
    else
      return NULL;
  }
  
  int *mapObj_getLayersIndexByGroup(mapObj* self, char *groupname,
                                    int *pnCount)
  {
    return msGetLayersIndexByGroup(self, groupname, pnCount);
  }
  
  
  int mapObj_getSymbolByName(mapObj* self, char *name)
  {
    return msGetSymbolIndex(&self->symbolset, name, MS_TRUE);
  }
  
  void mapObj_prepareQuery(mapObj* self)
  {
    int status;
  
    status = msCalculateScale(self->extent, self->units, self->width, self->height, self->resolution, &self->scaledenom);
    if(status != MS_SUCCESS) self->scaledenom = -1; // degenerate extents ok here
  }
  
  imageObj *mapObj_prepareImage(mapObj* self)
  {
    return msPrepareImage(self, MS_FALSE);
  }
  
  imageObj *mapObj_draw(mapObj* self)
  {
    return msDrawMap(self, MS_FALSE);
  }
  
  imageObj *mapObj_drawQuery(mapObj* self)
  {
    return msDrawMap(self, MS_TRUE);
  }
  
  imageObj *mapObj_drawLegend(mapObj* self)
  {
    return msDrawLegend(self, MS_FALSE);
  }
  
  
  imageObj *mapObj_drawScalebar(mapObj* self)
  {
    return msDrawScalebar(self);
  }
  
  imageObj *mapObj_drawReferenceMap(mapObj* self)
  {
    return msDrawReferenceMap(self);
  }
  
  //TODO
  int mapObj_embedScalebar(mapObj* self, imageObj *img)
  {
    return msEmbedScalebar(self, img);
  }
  
  //TODO
  int mapObj_embedLegend(mapObj* self, imageObj *img)
  {
    return msEmbedLegend(self, img);
  }
  
  int mapObj_drawLabelCache(mapObj* self, imageObj *img)
  {
    return msDrawLabelCache(img, self);
  }
  
  labelCacheMemberObj* mapObj_getLabel(mapObj* self, int i)
  {
    return msGetLabelCacheMember(&(self->labelcache), i);
  }
  
  int mapObj_queryByPoint(mapObj* self, pointObj *point, int mode, double buffer)
  {
    msInitQuery(&(self->query));
  
    self->query.type = MS_QUERY_BY_POINT;
    self->query.mode = mode;
    self->query.point = *point;
    self->query.buffer = buffer;
  
    return msQueryByPoint(self);
  }
  
  int mapObj_queryByRect(mapObj* self, rectObj rect)
  {
    msInitQuery(&(self->query));
  
    self->query.type = MS_QUERY_BY_RECT;
    self->query.mode = MS_QUERY_MULTIPLE;
    self->query.rect = rect;
  
    return msQueryByRect(self);
  }
  
  int mapObj_queryByFeatures(mapObj* self, int slayer)
  {
    self->query.slayer = slayer;
    return msQueryByFeatures(self);
  }
  
  int mapObj_queryByFilter(mapObj* self, char *string)
  {
    msInitQuery(&(self->query));
  
    self->query.type = MS_QUERY_BY_FILTER;
  
    self->query.filter = (expressionObj *) malloc(sizeof(expressionObj));
    self->query.filter->compiled = MS_FALSE;
    self->query.filter->flags = 0;
    self->query.filter->tokens = self->query.filter->curtoken = NULL;
    self->query.filter->string = strdup(string);
    self->query.filter->type = 2000; /* MS_EXPRESSION: lot's of conflicts in mapfile.h */
  
    self->query.rect = self->extent;
  
    return msQueryByFilter(self);
  }
  
  int mapObj_queryByShape(mapObj *self, shapeObj *shape)
  {
    msInitQuery(&(self->query));
  
    self->query.type = MS_QUERY_BY_SHAPE;
    self->query.mode = MS_QUERY_MULTIPLE;
    self->query.shape = (shapeObj *) malloc(sizeof(shapeObj));
    msInitShape(self->query.shape);
    msCopyShape(shape, self->query.shape);
  
    return msQueryByShape(self);
  }
  
  int mapObj_queryByIndex(mapObj *self, int qlayer, int tileindex, int shapeindex, int bAddToQuery)
  {
    msInitQuery(&(self->query));
  
    self->query.type = MS_QUERY_BY_INDEX;
    self->query.mode = MS_QUERY_SINGLE;
    self->query.tileindex = tileindex;
    self->query.shapeindex = shapeindex;
    self->query.clear_resultcache = !bAddToQuery;
    self->query.layer = qlayer;
  
    return msQueryByIndex(self);
  }
  
  int mapObj_saveQuery(mapObj *self, char *filename, int results)
  {
    return msSaveQuery(self, filename, results);
  }
  int mapObj_loadQuery(mapObj *self, char *filename)
  {
    return msLoadQuery(self, filename);
  }
  void mapObj_freeQuery(mapObj *self, int qlayer)
  {
    msQueryFree(self, qlayer);
  }
  
  int mapObj_setWKTProjection(mapObj *self, char *string)
  {
    return msOGCWKT2ProjectionObj(string, &(self->projection), self->debug);
  }
  
  char *mapObj_getProjection(mapObj* self)
  {
    return msGetProjectionString(&self->projection);
  }
  
  int mapObj_setProjection(mapObj* self, char *string)
  {
    return(msLoadProjectionString(&(self->projection), string));
  }
  
  int mapObj_save(mapObj* self, char *filename)
  {
    return msSaveMap(self, filename);
  }
  
  char *mapObj_getMetaData(mapObj *self, char *name)
  {
    return(msLookupHashTable(&(self->web.metadata), name));
  }
  
  int mapObj_setMetaData(mapObj *self, char *name, char *value)
  {
    if (msInsertHashTable(&(self->web.metadata), name, value) == NULL)
      return MS_FAILURE;
    return MS_SUCCESS;
  }
  
  int mapObj_removeMetaData(mapObj *self, char *name)
  {
    return(msRemoveHashTable(&(self->web.metadata), name));
  }
  
  int mapObj_moveLayerup(mapObj *self, int layerindex)
  {
    return msMoveLayerUp(self, layerindex);
  }
  
  int mapObj_moveLayerdown(mapObj *self, int layerindex)
  {
    return msMoveLayerDown(self, layerindex);
  }
  
  int *mapObj_getLayersdrawingOrder(mapObj *self)
  {
    return self->layerorder;
  }
  
  int mapObj_setLayersdrawingOrder(mapObj *self, int *panIndexes)
  {
    return msSetLayersdrawingOrder(self, panIndexes);
  }
  
  char *mapObj_processTemplate(mapObj *self, int bGenerateImages,
                               char **names, char **values,
                               int numentries)
  {
    return msProcessTemplate(self, bGenerateImages,
                             names, values, numentries);
  }
  
  char *mapObj_processLegendTemplate(mapObj *self,
                                     char **names, char **values,
                                     int numentries)
  {
    return msProcessLegendTemplate(self, names, values, numentries);
  }
  
  
  char *mapObj_processQueryTemplate(mapObj *self, int bGenerateImages,
                                    char **names, char **values,
                                    int numentries)
  {
    return msProcessQueryTemplate(self, bGenerateImages, names, values,
                                  numentries);
  }
  
  int mapObj_setSymbolSet(mapObj *self,
                          char *szFileName)
  {
    msFreeSymbolSet(&self->symbolset);
    msInitSymbolSet(&self->symbolset);
  
    // Set symbolset filename
    self->symbolset.filename = strdup(szFileName);
  
    // Symbolset shares same fontset as main mapfile
    self->symbolset.fontset = &(self->fontset);
  
    return msLoadSymbolSet(&self->symbolset, self);
  }
  
  int mapObj_getNumSymbols(mapObj *self)
  {
    return self->symbolset.numsymbols;
  }
  
  int mapObj_setFontSet(mapObj *self, char *szFileName)
  {
    msFreeFontSet(&(self->fontset));
    msInitFontSet(&(self->fontset));
  
    // Set fontset filename
    self->fontset.filename = strdup(szFileName);
  
    return msLoadFontSet(&(self->fontset), self);
  }
  
  int mapObj_saveMapContext(mapObj *self, char *szFilename)
  {
    return msSaveMapContext(self, szFilename);
  }
  
  int mapObj_loadMapContext(mapObj *self, char *szFilename, int bUniqueLayerName)
  {
    return msLoadMapContext(self, szFilename, bUniqueLayerName);
  }
  
  
  
  int mapObj_selectOutputFormat(mapObj *self,
                                const char *imagetype)
  {
    outputFormatObj *format = NULL;
  
    format = msSelectOutputFormat(self, imagetype);
    if (format) {
      msApplyOutputFormat( &(self->outputformat), format,
                           self->transparent, self->interlace,
                           self->imagequality );
      return(MS_SUCCESS);
    }
    return(MS_FAILURE);
  
  }
  
  int mapObj_applySLD(mapObj *self, char *sld)
  {
    return msSLDApplySLD(self, sld, -1, NULL, NULL);
  }
  int mapObj_applySLDURL(mapObj *self, char *sld)
  {
    return msSLDApplySLDURL(self, sld, -1, NULL, NULL);
  }
  
  char *mapObj_generateSLD(mapObj *self)
  {
    return msSLDGenerateSLD(self, -1, NULL);
  }
  
  
  int mapObj_loadOWSParameters(mapObj *self, cgiRequestObj *request,
                               char *wmtver_string)
  {
    return msMapLoadOWSParameters(self, request, wmtver_string);
  }
  
  int mapObj_OWSDispatch(mapObj *self, cgiRequestObj *req )
  {
    return msOWSDispatch( self, req, MS_TRUE);
  }
  
  int mapObj_insertLayer(mapObj *self, layerObj *layer, int index)
  {
    if (self && layer)
      return msInsertLayer(self, layer, index);
  
    return -1;
  }
  
  layerObj *mapObj_removeLayer(mapObj *self, int layerindex)
  {
    return msRemoveLayer(self, layerindex);
  }
  
  int mapObj_setCenter(mapObj *self, pointObj *center)
  {
    return msMapSetCenter(self, center);
  }
  
  int mapObj_offsetExtent(mapObj *self, double x, double y)
  {
    return msMapOffsetExtent(self, x, y);
  }
  
  int mapObj_scaleExtent(mapObj *self, double zoomfactor, double minscaledenom,
                         double maxscaledenom)
  {
    return msMapScaleExtent(self, zoomfactor, minscaledenom, maxscaledenom);
  }
  
  char *mapObj_convertToString(mapObj *self)
  {
    return msWriteMapToString(self);
  }
  
  /**********************************************************************
   * class extensions for layerObj, always within the context of a map
   **********************************************************************/
  layerObj *layerObj_new(mapObj *map)
  {
    if(msGrowMapLayers(map) == NULL)
      return(NULL);
  
    if(initLayer((map->layers[map->numlayers]), map) == -1)
      return(NULL);
  
    map->layers[map->numlayers]->index = map->numlayers;
    //Update the layer order list with the layer's index.
    map->layerorder[map->numlayers] = map->numlayers;
  
    map->numlayers++;
  
    return (map->layers[map->numlayers-1]);
  }
  
  void layerObj_destroy(layerObj *self)
  {
    /* if the layer has a parent_map, let's the map object destroy it */
    if ((self->map == NULL) && (self->refcount == 1)) {
      /* if there is no other PHP Object that use this C layer object, delete it */
      freeLayer(self);
      free(self);
      self = NULL;
    } else {
      MS_REFCNT_DECR(self);
    }
    return;
  }
  
  layerObj *layerObj_clone(layerObj *layer)
  {
    layerObj *dstLayer;
    dstLayer = (layerObj *)malloc(sizeof(layerObj));
    initLayer(dstLayer, layer->map);
    msCopyLayer(dstLayer, layer);
    return dstLayer;
  }
  
  
  int layerObj_updateFromString(layerObj *self, char *snippet)
  {
    return msUpdateLayerFromString(self, snippet, MS_FALSE);
  }
  
  char *layerObj_convertToString(layerObj *self)
  {
    return msWriteLayerToString(self);
  }
  
  int layerObj_open(layerObj *self)
  {
    return msLayerOpen(self);
  }
  
  
  int layerObj_whichShapes(layerObj *self, rectObj *poRect)
  {
    int oldconnectiontype = self->connectiontype;
    self->connectiontype = MS_INLINE;
  
    if(msLayerWhichItems(self, MS_FALSE, NULL) != MS_SUCCESS) {
      self->connectiontype = oldconnectiontype;
      return MS_FAILURE;
    }
    self->connectiontype = oldconnectiontype;
  
    return msLayerWhichShapes(self, *poRect, MS_FALSE);
  }
  
  
  shapeObj *layerObj_nextShape(layerObj *self)
  {
    int status;
    shapeObj *shape;
  
    shape = (shapeObj *)malloc(sizeof(shapeObj));
    if (!shape) return NULL;
    msInitShape(shape);
  
    status = msLayerNextShape(self, shape);
    if(status != MS_SUCCESS) {
      msFreeShape(shape);
      free(shape);
      return NULL;
    } else
      return shape;
  }
  
  void layerObj_close(layerObj *self)
  {
    msLayerClose(self);
  }
  
  resultObj *layerObj_getResult(layerObj *self, int i)
  {
    if(!self->resultcache) return NULL;
  
    if(i >= 0 && i < self->resultcache->numresults)
      return &self->resultcache->results[i];
    else
      return NULL;
  }
  
  classObj *layerObj_getClass(layerObj *self, int i)   // returns an EXISTING class
  {
    if(i >= 0 && i < self->numclasses)
      return (self->class[i]);
    else
      return(NULL);
  }
  
  int layerObj_getClassIndex(layerObj *self, mapObj *map, shapeObj *shape,
                             int *classgroup, int numclasses)
  {
    return msShapeGetClass(self, map, shape, classgroup, numclasses);
  }
  
  int layerObj_draw(layerObj *self, mapObj *map, imageObj *img)
  {
    return msDrawLayer(map, self, img);
  }
  
  int layerObj_drawQuery(layerObj *self, mapObj *map, imageObj *img)
  {
    return msDrawQueryLayer(map, self, img);
  }
  
  int layerObj_queryByAttributes(layerObj *self, mapObj *map, char *qitem, char *qstring, int mode)
  {
    int status;
    int retval;
  
    msInitQuery(&(map->query));
  
    map->query.type = MS_QUERY_BY_ATTRIBUTE;
    map->query.mode = mode;
    if(qitem) map->query.item = strdup(qitem);
    if(qstring) map->query.str = strdup(qstring);
    map->query.layer = self->index;
    map->query.rect = map->extent;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByAttributes(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_queryByPoint(layerObj *self, mapObj *map, pointObj *point, int mode, double buffer)
  {
    int status;
    int retval;
  
    msInitQuery(&(map->query));
  
    map->query.type = MS_QUERY_BY_POINT;
    map->query.mode = mode;
    map->query.point = *point;
    map->query.buffer = buffer;
    map->query.layer = self->index;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByPoint(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_queryByRect(layerObj *self, mapObj *map, rectObj rect)
  {
    int status;
    int retval;
  
    msInitQuery(&(map->query));
  
    map->query.type = MS_QUERY_BY_RECT;
    map->query.mode = MS_QUERY_MULTIPLE;
    map->query.rect = rect;
    map->query.layer = self->index;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByRect(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_queryByFeatures(layerObj *self, mapObj *map, int slayer)
  {
    int status;
    int retval;
  
    map->query.slayer = slayer;
    map->query.layer = self->index;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByFeatures(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_queryByShape(layerObj *self, mapObj *map, shapeObj *shape)
  {
    int status;
    int retval;
  
    msInitQuery(&(map->query));
  
    map->query.type = MS_QUERY_BY_SHAPE;
    map->query.mode = MS_QUERY_MULTIPLE;
    map->query.shape = (shapeObj *) malloc(sizeof(shapeObj));
    msInitShape(map->query.shape);
    msCopyShape(shape, map->query.shape);
    map->query.layer = self->index;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByShape(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_queryByFilter(layerObj *self, mapObj *map, char *string)
  {
    int status;
    int retval;
  
    msInitQuery(&(map->query));
  
    map->query.type = MS_QUERY_BY_FILTER;
  
    map->query.filter = (expressionObj *) malloc(sizeof(expressionObj));
    map->query.filter->string = strdup(string);
    map->query.filter->type = 2000; /* MS_EXPRESSION: lot's of conflicts in mapfile.h */
    map->query.filter->compiled = MS_FALSE;
    map->query.filter->flags = 0;
    map->query.filter->tokens = map->query.filter->curtoken = NULL;
  
    map->query.layer = self->index;
    map->query.rect = map->extent;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByFilter(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_queryByIndex(layerObj *self, mapObj *map, int tileindex, int shapeindex, int addtoquery)
  {
    int status;
    int retval;
  
    msInitQuery(&(map->query));
  
    map->query.type = MS_QUERY_BY_INDEX;
    map->query.mode = MS_QUERY_SINGLE;
    map->query.tileindex = tileindex;
    map->query.shapeindex = shapeindex;
    map->query.clear_resultcache = !addtoquery;
    map->query.layer = self->index;
  
    status = self->status;
    self->status = MS_ON;
    retval = msQueryByIndex(map);
    self->status = status;
  
    return retval;
  }
  
  int layerObj_setFilter(layerObj *self, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->filter);
      return MS_SUCCESS;
    } else return msLoadExpressionString(&self->filter, string);
  }
  
  char *layerObj_getFilter(layerObj *self)
  {
    return msGetExpressionString(&(self->filter));
  }
  
  int layerObj_setWKTProjection(layerObj *self, char *string)
  {
    self->project = MS_TRUE;
    return msOGCWKT2ProjectionObj(string, &(self->projection), self->debug);
  }
  
  char *layerObj_getProjection(layerObj* self)
  {
    return msGetProjectionString(&self->projection);
  }
  
  int layerObj_setProjection(layerObj *self, char *string)
  {
    int nReturn;
    nReturn = msLoadProjectionString(&(self->projection), string);
    if (nReturn == MS_SUCCESS)
      self->project = MS_TRUE;
    return nReturn;
  
  }
  
  int layerObj_addFeature(layerObj *self, shapeObj *shape)
  {
    if(self->features != NULL && self->features->tailifhead != NULL)
      shape->index = self->features->tailifhead->shape.index + 1;
    else
      shape->index = 0;
    if(insertFeatureList(&(self->features), shape) == NULL)
      return MS_FAILURE;
    else
      return MS_SUCCESS;
  }
  
  char *layerObj_getMetaData(layerObj *self, char *name)
  {
    return(msLookupHashTable(&(self->metadata), name));
  }
  
  
  int layerObj_setMetaData(layerObj *self, char *name, char *value)
  {
    if (msInsertHashTable(&(self->metadata), name, value) == NULL)
      return MS_FAILURE;
    return MS_SUCCESS;
  }
  
  int layerObj_removeMetaData(layerObj *self, char *name)
  {
    return(msRemoveHashTable(&(self->metadata), name));
  }
  
  char *layerObj_getWMSFeatureInfoURL(layerObj *self, mapObj *map, int click_x, int click_y,
                                      int feature_count, char *info_format)
  {
    // NOTE: the returned string should be freed by the caller but right
    // now we're leaking it.
    return(msWMSGetFeatureInfoURL(map, self, click_x, click_y,
                                  feature_count, info_format));
  }
  
  char *layerObj_executeWFSGetFeature(layerObj *self)
  {
    return (msWFSExecuteGetFeature(self));
  }
  
  int layerObj_applySLD(layerObj *self, char *sld, char *stylelayer)
  {
    return msSLDApplySLD(self->map, sld, self->index, stylelayer, NULL);
  }
  int layerObj_applySLDURL(layerObj *self, char *sld, char *stylelayer)
  {
    return msSLDApplySLDURL(self->map, sld, self->index, stylelayer, NULL);
  }
  
  char *layerObj_generateSLD(layerObj *self)
  {
    return msSLDGenerateSLD(self->map, self->index, NULL);
  }
  
  int layerObj_moveClassUp(layerObj *self, int index)
  {
    return msMoveClassUp(self, index);
  }
  
  int layerObj_moveClassDown(layerObj *self, int index)
  {
    return msMoveClassDown(self, index);
  }
  
  classObj *layerObj_removeClass(layerObj *self, int index)
  {
    return msRemoveClass(self, index);
  }
  
  int layerObj_setConnectionType(layerObj *self, int connectiontype,
                                 const char *library_str)
  {
    /* Caller is responsible to close previous layer correctly before calling
     * msConnectLayer()
     */
    if (msLayerIsOpen(self))
      msLayerClose(self);
  
    return msConnectLayer(self, connectiontype, library_str);
  }
  
  /**********************************************************************
   * class extensions for labelObj
   **********************************************************************/
  labelObj *labelObj_new()
  {
    labelObj *label;
  
    label = (labelObj *)malloc(sizeof(labelObj));
    if(!label)
      return(NULL);
  
    initLabel(label);
  
    return label;
  }
  
  void labelObj_destroy(labelObj *self)
  {
    if (freeLabel(self) == MS_SUCCESS)
      free(self);
  
  }
  
  labelObj *labelObj_clone(labelObj *label)
  {
    labelObj *dstLabel;
    dstLabel = (labelObj *)malloc(sizeof(labelObj));
    initLabel(dstLabel);
    dstLabel->font = NULL;
    msCopyLabel(dstLabel, label);
  
    return dstLabel;
  }
  
  int labelObj_updateFromString(labelObj *self, char *snippet)
  {
    return msUpdateLabelFromString(self, snippet, MS_FALSE);
  }
  
  char *labelObj_convertToString(labelObj *self)
  {
    return msWriteLabelToString(self);
  }
  
  int labelObj_moveStyleUp(labelObj *self, int index)
  {
    return msMoveLabelStyleUp(self, index);
  }
  
  int labelObj_moveStyleDown(labelObj *self, int index)
  {
    return msMoveLabelStyleDown(self, index);
  }
  
  int labelObj_deleteStyle(labelObj *self, int index)
  {
    return msDeleteLabelStyle(self, index);
  }
  
  int labelObj_setExpression(labelObj *self, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->expression);
      return MS_SUCCESS;
    } else return msLoadExpressionString(&self->expression, string);
  }
  
  char *labelObj_getExpressionString(labelObj *self)
  {
    return msGetExpressionString(&(self->expression));
  }
  
  int labelObj_setText(labelObj *self, layerObj *layer, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->text);
      return MS_SUCCESS;
    }
    return msLoadExpressionString(&self->text, string);
  }
  
  char *labelObj_getTextString(labelObj *self)
  {
    return msGetExpressionString(&(self->text));
  }
  
  /**********************************************************************
   * class extensions for legendObj
   **********************************************************************/
  int legendObj_updateFromString(legendObj *self, char *snippet)
  {
    return msUpdateLegendFromString(self, snippet, MS_FALSE);
  }
  
  char *legendObj_convertToString(legendObj *self)
  {
    return msWriteLegendToString(self);
  }
  
  /**********************************************************************
   * class extensions for queryMapObj
   **********************************************************************/
  int queryMapObj_updateFromString(queryMapObj *self, char *snippet)
  {
    return msUpdateQueryMapFromString(self, snippet, MS_FALSE);
  }
  
  char *queryMapObj_convertToString(queryMapObj *self)
  {
    return msWriteQueryMapToString(self);
  }
  
  /**********************************************************************
   * class extensions for referenceMapObj
   **********************************************************************/
  
  int referenceMapObj_updateFromString(referenceMapObj *self, char *snippet)
  {
    return msUpdateReferenceMapFromString(self, snippet, MS_FALSE);
  }
  
  char *referenceMapObj_convertToString(referenceMapObj *self)
  {
    return msWriteReferenceMapToString(self);
  }
  
  /**********************************************************************
   * class extensions for scaleBarObj
   **********************************************************************/
  
  int scalebarObj_updateFromString(scalebarObj *self, char *snippet)
  {
    return msUpdateScalebarFromString(self, snippet, MS_FALSE);
  }
  
  char *scalebarObj_convertToString(scalebarObj *self)
  {
    return msWriteScalebarToString(self);
  }
  
  /**********************************************************************
   * class extensions for webObj
   **********************************************************************/
  
  int webObj_updateFromString(webObj *self, char *snippet)
  {
    return msUpdateWebFromString(self, snippet, MS_FALSE);
  }
  
  char *webObj_convertToString(webObj *self)
  {
    return msWriteWebToString(self);
  }
  
  /**********************************************************************
   * class extensions for classObj, always within the context of a layer
   **********************************************************************/
  classObj *classObj_new(layerObj *layer, classObj *class)
  {
    if(msGrowLayerClasses(layer) == NULL)
      return NULL;
  
    if(initClass((layer->class[layer->numclasses])) == -1)
      return NULL;
  
    if (class) {
      msCopyClass((layer->class[layer->numclasses]), class, layer);
      layer->class[layer->numclasses]->layer = layer;
    }
  
    layer->class[layer->numclasses]->type = layer->type;
    layer->class[layer->numclasses]->layer = layer;
  
    layer->numclasses++;
  
    return (layer->class[layer->numclasses-1]);
  }
  
  int classObj_addLabel(classObj *self, labelObj *label)
  {
    return msAddLabelToClass(self, label);
  }
  
  labelObj *classObj_removeLabel(classObj *self, int index)
  {
    return msRemoveLabelFromClass(self, index);
  }
  
  labelObj *classObj_getLabel(classObj *self, int i)   // returns an EXISTING label
  {
    if(i >= 0 && i < self->numlabels)
      return (self->labels[i]);
    else
      return(NULL);
  }
  
  int classObj_updateFromString(classObj *self, char *snippet)
  {
    return msUpdateClassFromString(self, snippet, MS_FALSE);
  }
  
  char *classObj_convertToString(classObj *self)
  {
    return msWriteClassToString(self);
  }
  
  void  classObj_destroy(classObj *self)
  {
    return; /* do nothing, map deconstrutor takes care of it all */
  }
  
  int classObj_setExpression(classObj *self, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->expression);
      return MS_SUCCESS;
    } else return msLoadExpressionString(&self->expression, string);
  }
  
  char *classObj_getExpressionString(classObj *self)
  {
    return msGetExpressionString(&(self->expression));
  }
  
  int classObj_setText(classObj *self, layerObj *layer, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->text);
      return MS_SUCCESS;
    }
    return msLoadExpressionString(&self->text, string);
  }
  
  char *classObj_getTextString(classObj *self)
  {
    return msGetExpressionString(&(self->text));
  }
  
  int classObj_drawLegendIcon(classObj *self, mapObj *map, layerObj *layer, int width, int height, imageObj *dstImg, int dstX, int dstY)
  {
  #ifdef USE_GD
    msClearLayerPenValues(layer); // just in case the mapfile has already been processed
  #endif
    return msDrawLegendIcon(map, layer, self, width, height, dstImg, dstX, dstY, MS_TRUE);
  }
  
  imageObj *classObj_createLegendIcon(classObj *self, mapObj *map, layerObj *layer, int width, int height)
  {
    return msCreateLegendIcon(map, layer, self, width, height, MS_TRUE);
  }
  
  
  int classObj_setSymbolByName(classObj *self, mapObj *map, char* pszSymbolName)
  {
    /*
     self->symbol = msGetSymbolIndex(&map->symbolset, pszSymbolName, MS_TRUE);
      return self->symbol;
    */
    return -1;
  }
  
  int classObj_setOverlaySymbolByName(classObj *self, mapObj *map, char* pszOverlaySymbolName)
  {
    /*
      self->overlaysymbol = msGetSymbolIndex(&map->symbolset, pszOverlaySymbolName, MS_TRUE);
      return self->overlaysymbol;
    */
    return -1;
  
  }
  
  classObj *classObj_clone(classObj *class, layerObj *layer)
  {
    classObj *dstClass;
    dstClass = (classObj *)malloc(sizeof(classObj));
  
    initClass(dstClass);
    msCopyClass(dstClass, class, layer);
  
    dstClass->type = layer->type;
  
    return dstClass;
  }
  
  int classObj_moveStyleUp(classObj *self, int index)
  {
    return msMoveStyleUp(self, index);
  }
  
  int classObj_moveStyleDown(classObj *self, int index)
  {
    return msMoveStyleDown(self, index);
  }
  
  int classObj_deleteStyle(classObj *self, int index)
  {
    return msDeleteStyle(self, index);
  }
  
  /**********************************************************************
   * class extensions for pointObj, useful many places
   **********************************************************************/
  pointObj *pointObj_new()
  {
    return (pointObj *)malloc(sizeof(pointObj));
  }
  
  void pointObj_destroy(pointObj *self)
  {
    free(self);
  }
  
  int pointObj_project(pointObj *self, projectionObj *in, projectionObj *out)
  {
    return msProjectPoint(in, out, self);
  }
  
  int pointObj_draw(pointObj *self, mapObj *map, layerObj *layer,
                    imageObj *img, int class_index, char *label_string)
  {
    return msDrawPoint(map, layer, self, img, class_index, label_string);
  }
  
  double pointObj_distanceToPoint(pointObj *self, pointObj *point)
  {
    return msDistancePointToPoint(self, point);
  }
  
  double pointObj_distanceToLine(pointObj *self, pointObj *a, pointObj *b)
  {
    return msDistancePointToSegment(self, a, b);
  }
  
  double pointObj_distanceToShape(pointObj *self, shapeObj *shape)
  {
    return msDistancePointToShape(self, shape);
  }
  
  /**********************************************************************
   * class extensions for lineObj (eg. a line or group of points),
   * useful many places
   **********************************************************************/
  lineObj *lineObj_new()
  {
    lineObj *line;
  
    line = (lineObj *)malloc(sizeof(lineObj));
    if(!line)
      return(NULL);
  
    line->numpoints=0;
    line->point=NULL;
  
    return line;
  }
  
  void lineObj_destroy(lineObj *self)
  {
    free(self->point);
    free(self);
  }
  
  lineObj *lineObj_clone(lineObj *line)
  {
    lineObj *dstLine;
    dstLine = (lineObj *)malloc(sizeof(lineObj));
    dstLine->numpoints= line->numpoints;
    dstLine->point = (pointObj *)malloc(sizeof(pointObj)*(dstLine->numpoints));
    msCopyLine(dstLine, line);
  
  
    return dstLine;
  }
  
  int lineObj_project(lineObj *self, projectionObj *in, projectionObj *out)
  {
    return msProjectLine(in, out, self);
  }
  
  pointObj *lineObj_get(lineObj *self, int i)
  {
    if(i<0 || i>=self->numpoints)
      return NULL;
    else
      return &(self->point[i]);
  }
  
  int lineObj_add(lineObj *self, pointObj *p)
  {
    if(self->numpoints == 0) { /* new */
      self->point = (pointObj *)malloc(sizeof(pointObj));
      if(!self->point)
        return MS_FAILURE;
    } else { /* extend array */
      self->point = (pointObj *)realloc(self->point, sizeof(pointObj)*(self->numpoints+1));
      if(!self->point)
        return MS_FAILURE;
    }
  
    self->point[self->numpoints].x = p->x;
    self->point[self->numpoints].y = p->y;
  #ifdef USE_POINT_Z_M
    self->point[self->numpoints].m = p->m;
  #endif
    self->numpoints++;
  
    return MS_SUCCESS;
  }
  
  
  /**********************************************************************
   * class extensions for shapeObj
   **********************************************************************/
  shapeObj *shapeObj_new(int type)
  {
    shapeObj *shape;
  
    shape = (shapeObj *)malloc(sizeof(shapeObj));
    if(!shape)
      return NULL;
  
    msInitShape(shape);
    shape->type = type;
    return shape;
  }
  
  void shapeObj_destroy(shapeObj *self)
  {
    msFreeShape(self);
    free(self);
  }
  
  int shapeObj_project(shapeObj *self, projectionObj *in, projectionObj *out)
  {
    return msProjectShape(in, out, self);
  }
  
  lineObj *shapeObj_get(shapeObj *self, int i)
  {
    if(i<0 || i>=self->numlines)
      return NULL;
    else
      return &(self->line[i]);
  }
  
  int shapeObj_add(shapeObj *self, lineObj *line)
  {
    return msAddLine(self, line);
  }
  
  int shapeObj_draw(shapeObj *self, mapObj *map, layerObj *layer,
                    imageObj *img)
  {
    return msDrawShape(map, layer, self, img, -1, MS_DRAWMODE_FEATURES|MS_DRAWMODE_LABELS);
  }
  
  void shapeObj_setBounds(shapeObj *self)
  {
    int i, j;
  
    self->bounds.minx = self->bounds.maxx = self->line[0].point[0].x;
    self->bounds.miny = self->bounds.maxy = self->line[0].point[0].y;
  
    for( i=0; i<self->numlines; i++ ) {
      for( j=0; j<self->line[i].numpoints; j++ ) {
        self->bounds.minx = MS_MIN(self->bounds.minx, self->line[i].point[j].x);
        self->bounds.maxx = MS_MAX(self->bounds.maxx, self->line[i].point[j].x);
        self->bounds.miny = MS_MIN(self->bounds.miny, self->line[i].point[j].y);
        self->bounds.maxy = MS_MAX(self->bounds.maxy, self->line[i].point[j].y);
      }
    }
  
    return;
  }
  
  int shapeObj_copy(shapeObj *self, shapeObj *dest)
  {
    return(msCopyShape(self, dest));
  }
  
  int shapeObj_contains(shapeObj *self, pointObj *point)
  {
    if(self->type == MS_SHAPE_POLYGON)
      return msIntersectPointPolygon(point, self);
  
    return -1;
  }
  
  int shapeObj_intersects(shapeObj *self, shapeObj *shape)
  {
    switch(self->type) {
      case(MS_SHAPE_LINE):
        switch(shape->type) {
          case(MS_SHAPE_LINE):
            return msIntersectPolylines(self, shape);
          case(MS_SHAPE_POLYGON):
            return msIntersectPolylinePolygon(self, shape);
        }
        break;
      case(MS_SHAPE_POLYGON):
        switch(shape->type) {
          case(MS_SHAPE_LINE):
            return msIntersectPolylinePolygon(shape, self);
          case(MS_SHAPE_POLYGON):
            return msIntersectPolygons(self, shape);
        }
        break;
    }
  
    return -1;
  }
  
  pointObj *shapeObj_getpointusingmeasure(shapeObj *self, double m)
  {
    if (self)
      return msGetPointUsingMeasure(self, m);
  
    return NULL;
  }
  
  pointObj *shapeObj_getmeasureusingpoint(shapeObj *self, pointObj *point)
  {
    if (self)
      return msGetMeasureUsingPoint(self, point);
  
    return NULL;
  }
  
  
  shapeObj *shapeObj_buffer(shapeObj *self, double width)
  {
    return msGEOSBuffer(self, width);
  }
  
  
  shapeObj *shapeObj_simplify(shapeObj *self, double tolerance)
  {
    return msGEOSSimplify(self, tolerance);
  }
  
  
  shapeObj *shapeObj_topologypreservingsimplify(shapeObj *self, double tolerance)
  {
    return msGEOSTopologyPreservingSimplify(self, tolerance);
  }
  
  
  shapeObj *shapeObj_convexHull(shapeObj *self)
  {
    return msGEOSConvexHull(self);
  }
  
  shapeObj *shapeObj_boundary(shapeObj *self)
  {
    return msGEOSBoundary(self);
  }
  
  int shapeObj_contains_geos(shapeObj *self, shapeObj *shape)
  {
    return msGEOSContains(self, shape);
  }
  
  shapeObj *shapeObj_Union(shapeObj *self, shapeObj *shape)
  {
    return msGEOSUnion(self, shape);
  }
  
  shapeObj *shapeObj_intersection(shapeObj *self, shapeObj *shape)
  {
    return msGEOSIntersection(self, shape);
  }
  
  shapeObj *shapeObj_difference(shapeObj *self, shapeObj *shape)
  {
    return msGEOSDifference(self, shape);
  }
  
  shapeObj *shapeObj_symdifference(shapeObj *self, shapeObj *shape)
  {
    return msGEOSSymDifference(self, shape);
  }
  
  int shapeObj_overlaps(shapeObj *self, shapeObj *shape)
  {
    return msGEOSOverlaps(self, shape);
  }
  
  int shapeObj_within(shapeObj *self, shapeObj *shape)
  {
    return msGEOSWithin(self, shape);
  }
  
  int shapeObj_crosses(shapeObj *self, shapeObj *shape)
  {
    return msGEOSCrosses(self, shape);
  }
  
  int shapeObj_touches(shapeObj *self, shapeObj *shape)
  {
    return msGEOSTouches(self, shape);
  }
  
  int shapeObj_equals(shapeObj *self, shapeObj *shape)
  {
    return msGEOSEquals(self, shape);
  }
  
  int shapeObj_disjoint(shapeObj *self, shapeObj *shape)
  {
    return msGEOSDisjoint(self, shape);
  }
  
  
  pointObj *shapeObj_getcentroid(shapeObj *self)
  {
    return msGEOSGetCentroid(self);
  }
  
  double shapeObj_getarea(shapeObj *self)
  {
    return msGEOSArea(self);
  }
  
  double shapeObj_getlength(shapeObj *self)
  {
    return msGEOSLength(self);
  }
  
  pointObj *shapeObj_getLabelPoint(shapeObj *self)
  {
    pointObj *point = (pointObj *)calloc(1, sizeof(pointObj));
    if (point == NULL) {
      msSetError(MS_MEMERR, "Failed to allocate memory for point", "getLabelPoint()");
      return NULL;
    }
  
    if(self->type == MS_SHAPE_POLYGON && msPolygonLabelPoint(self, point, -1) == MS_SUCCESS)
      return point;
  
    free(point);
    return NULL;
  }
  
  
  /**********************************************************************
   * class extensions for rectObj
   **********************************************************************/
  rectObj *rectObj_new()
  {
    rectObj *rect;
  
    rect = (rectObj *)calloc(1, sizeof(rectObj));
    if(!rect)
      return(NULL);
  
    rect->minx = -1;
    rect->miny = -1;
    rect->maxx = -1;
    rect->maxy = -1;
  
    return(rect);
  }
  
  void rectObj_destroy(rectObj *self)
  {
    free(self);
  }
  
  int rectObj_project(rectObj *self, projectionObj *in, projectionObj *out)
  {
    return msProjectRect(in, out, self);
  }
  
  double rectObj_fit(rectObj *self, int width, int height)
  {
    return  msAdjustExtent(self, width, height);
  }
  
  int rectObj_draw(rectObj *self, mapObj *map, layerObj *layer,
                   imageObj *img, int classindex, char *text)
  {
    shapeObj shape;
  
    msInitShape(&shape);
    msRectToPolygon(*self, &shape);
    shape.classindex = classindex;
  
    if(text && layer->class[classindex]->numlabels > 0) {
      shape.text = strdup(text);
      msShapeGetAnnotation(layer,&shape);
    }
    
    msDrawShape(map, layer, &shape, img, -1, MS_DRAWMODE_FEATURES|MS_DRAWMODE_LABELS);
  
    msFreeShape(&shape);
  
    return 0;
  }
  
  /**********************************************************************
   * class extensions for shapefileObj
   **********************************************************************/
  shapefileObj *shapefileObj_new(char *filename, int type)
  {
    shapefileObj *shapefile;
    int status;
  
    shapefile = (shapefileObj *)calloc(1,sizeof(shapefileObj));
    if(!shapefile)
      return NULL;
  
    if(type == -1)
      status = msShapefileOpen(shapefile, "rb", filename, MS_TRUE);
    else if (type == -2)
      status = msShapefileOpen(shapefile, "rb+", filename, MS_TRUE);
    else
      status = msShapefileCreate(shapefile, filename, type);
  
    if(status == -1) {
      msShapefileClose(shapefile);
      free(shapefile);
      return NULL;
    }
  
    return(shapefile);
  }
  
  void shapefileObj_destroy(shapefileObj *self)
  {
    msShapefileClose(self);
    free(self);
  }
  
  int shapefileObj_get(shapefileObj *self, int i, shapeObj *shape)
  {
    if(i<0 || i>=self->numshapes)
      return -1;
  
    msFreeShape(shape); /* frees all lines and points before re-filling */
    msSHPReadShape(self->hSHP, i, shape);
    self->lastshape = i;
  
    return MS_SUCCESS;
  }
  
  int shapefileObj_getPoint(shapefileObj *self, int i, pointObj *point)
  {
    if(i<0 || i>=self->numshapes)
      return -1;
  
    return msSHPReadPoint(self->hSHP, i, point);
  }
  
  int shapefileObj_getTransformed(shapefileObj *self, mapObj *map,
                                  int i, shapeObj *shape)
  {
    if(i<0 || i>=self->numshapes)
      return -1;
  
    msFreeShape(shape); /* frees all lines and points before re-filling */
    msSHPReadShape(self->hSHP, i, shape);
    msTransformShapeSimplify(shape, map->extent, map->cellsize);
  
    return 0;
  }
  
  void shapefileObj_getExtent(shapefileObj *self, int i, rectObj *rect)
  {
    msSHPReadBounds(self->hSHP, i, rect);
  }
  
  int shapefileObj_add(shapefileObj *self, shapeObj *shape)
  {
    return msSHPWriteShape(self->hSHP, shape);
  }
  
  int shapefileObj_addPoint(shapefileObj *self, pointObj *point)
  {
    return msSHPWritePoint(self->hSHP, point);
  }
  
  /**********************************************************************
   * class extensions for projectionObj
   **********************************************************************/
  projectionObj *projectionObj_new(char *string)
  {
  
    int status;
    projectionObj *proj=NULL;
  
    proj = (projectionObj *)malloc(sizeof(projectionObj));
    if(!proj) return NULL;
    msInitProjection(proj);
  
    status = msLoadProjectionString(proj, string);
    if(status == -1) {
      msFreeProjection(proj);
      free(proj);
      return NULL;
    }
  
    return proj;
  }
  
  int projectionObj_getUnits(projectionObj *self)
  {
    return GetMapserverUnitUsingProj(self);
  }
  
  void projectionObj_destroy(projectionObj *self)
  {
    msFreeProjection(self);
    free(self);
  }
  
  projectionObj *projectionObj_clone(projectionObj *projection)
  {
    projectionObj *dstProjection;
    dstProjection = (projectionObj *)malloc(sizeof(projectionObj));
    msInitProjection(dstProjection);
    msCopyProjection(dstProjection, projection);
  
    return dstProjection;
  }
  
  /**********************************************************************
   * class extensions for labelCacheObj - TP mods
   **********************************************************************/
  void labelCacheObj_freeCache(labelCacheObj *self)
  {
    msFreeLabelCache(self);
  
  }
  
  /**********************************************************************
   * class extensions for DBFInfo - TP mods
   **********************************************************************/
  char *DBFInfo_getFieldName(DBFInfo *self, int iField)
  {
    static char pszFieldName[1000];
    int pnWidth;
    int pnDecimals;
    msDBFGetFieldInfo(self, iField, &pszFieldName[0], &pnWidth, &pnDecimals);
    return pszFieldName;
  }
  
  int DBFInfo_getFieldWidth(DBFInfo *self, int iField)
  {
    char pszFieldName[1000];
    int pnWidth;
    int pnDecimals;
    msDBFGetFieldInfo(self, iField, &pszFieldName[0], &pnWidth, &pnDecimals);
    return pnWidth;
  }
  
  int DBFInfo_getFieldDecimals(DBFInfo *self, int iField)
  {
    char pszFieldName[1000];
    int pnWidth;
    int pnDecimals;
    msDBFGetFieldInfo(self, iField, &pszFieldName[0], &pnWidth, &pnDecimals);
    return pnDecimals;
  }
  
  DBFFieldType DBFInfo_getFieldType(DBFInfo *self, int iField)
  {
    return msDBFGetFieldInfo(self, iField, NULL, NULL, NULL);
  }
  
  /**********************************************************************
   * class extensions for styleObj, always within the context of a class
   **********************************************************************/
  styleObj *styleObj_new(classObj *class, styleObj *style)
  {
    if(msGrowClassStyles(class) == NULL)
      return NULL;
  
    if(initStyle(class->styles[class->numstyles]) == -1)
      return NULL;
  
    if (style)
      msCopyStyle(class->styles[class->numstyles], style);
  
    class->numstyles++;
  
    return class->styles[class->numstyles-1];
  }
  
  styleObj *styleObj_label_new(labelObj *label, styleObj *style)
  {
    if(msGrowLabelStyles(label) == NULL)
      return NULL;
  
    if(initStyle(label->styles[label->numstyles]) == -1)
      return NULL;
  
    if (style)
      msCopyStyle(label->styles[label->numstyles], style);
  
    label->numstyles++;
  
    return label->styles[label->numstyles-1];
  }
  
  int styleObj_updateFromString(styleObj *self, char *snippet)
  {
    return msUpdateStyleFromString(self, snippet, MS_FALSE);
  }
  
  char *styleObj_convertToString(styleObj *self)
  {
    return msWriteStyleToString(self);
  }
  
  int styleObj_setSymbolByName(styleObj *self, mapObj *map, char* pszSymbolName)
  {
    self->symbol = msGetSymbolIndex(&map->symbolset, pszSymbolName, MS_TRUE);
    return self->symbol;
  }
  
  styleObj *styleObj_clone(styleObj *style)
  {
    styleObj *newstyle = NULL;
    if (!style)
      return NULL;
  
    newstyle = (styleObj *)malloc(sizeof(styleObj));
    initStyle(newstyle);
  
    msCopyStyle(newstyle, style);
  
    return newstyle;
  }
  
  void styleObj_setGeomTransform(styleObj *style, char *transform)
  {
    if (!style)
      return;
  
    msStyleSetGeomTransform(style, transform);
  }
  
  
  cgiRequestObj *cgirequestObj_new()
  {
    cgiRequestObj *request;
    request = msAllocCgiObj();
  
    return request;
  }
  
  int cgirequestObj_loadParams(cgiRequestObj *self,
                               char* (*getenv2)(const char*, void* thread_context),
                               char *raw_post_data,
                               ms_uint32 raw_post_data_length,
                               void* thread_context)
  {
    self->NumParams = loadParams(self, getenv2, raw_post_data, raw_post_data_length, thread_context);
    return self->NumParams;
  }
  
  
  void cgirequestObj_setParameter(cgiRequestObj *self, char *name, char *value)
  {
    int i;
  
    if (self->NumParams == MS_DEFAULT_CGI_PARAMS) {
      msSetError(MS_CHILDERR, "Maximum number of items, %d, has been reached", "setItem()", MS_DEFAULT_CGI_PARAMS);
    }
  
    for (i=0; i<self->NumParams; i++) {
      if (strcasecmp(self->ParamNames[i], name) == 0) {
        free(self->ParamValues[i]);
        self->ParamValues[i] = strdup(value);
        break;
      }
    }
    if (i == self->NumParams) {
      self->ParamNames[self->NumParams] = strdup(name);
      self->ParamValues[self->NumParams] = strdup(value);
      self->NumParams++;
    }
  }
  
  void cgirequestObj_addParameter(cgiRequestObj *self, char *name, char *value)
  {
    if (self->NumParams == MS_DEFAULT_CGI_PARAMS) {
      msSetError(MS_CHILDERR, "Maximum number of items, %d, has been reached", "addParameter()", MS_DEFAULT_CGI_PARAMS);
    }
    self->ParamNames[self->NumParams] = strdup(name);
    self->ParamValues[self->NumParams] = strdup(value);
    self->NumParams++;
  }
  
  char *cgirequestObj_getName(cgiRequestObj *self, int index)
  {
    if (index < 0 || index >= self->NumParams) {
      msSetError(MS_CHILDERR, "Invalid index, valid range is [0, %d]", "getName()", self->NumParams-1);
      return NULL;
    }
    return self->ParamNames[index];
  }
  
  char *cgirequestObj_getValue(cgiRequestObj *self, int index)
  {
    if (index < 0 || index >= self->NumParams) {
      msSetError(MS_CHILDERR, "Invalid index, valid range is [0, %d]", "getValue()", self->NumParams-1);
      return NULL;
    }
    return self->ParamValues[index];
  }
  
  char *cgirequestObj_getValueByName(cgiRequestObj *self, const char *name)
  {
    int i;
    for (i=0; i<self->NumParams; i++) {
      if (strcasecmp(self->ParamNames[i], name) == 0) {
        return self->ParamValues[i];
      }
    }
    return NULL;
  }
  void cgirequestObj_destroy(cgiRequestObj *self)
  {
    free(self);
  }
  
  
  /**********************************************************************
   * class extensions hashTableObj
   **********************************************************************/
  
  // New instance
  hashTableObj *hashTableObj_new()
  {
    return msCreateHashTable();
  }
  
  // set a hash item given key and value
  int hashTableObj_set(hashTableObj *self, const char *key, const char *value)
  {
    if (msInsertHashTable(self, key, value) == NULL) {
      return MS_FAILURE;
    }
    return MS_SUCCESS;
  }
  
  // get value from item by its key
  const char *hashTableObj_get(hashTableObj *self, const char *key)
  {
    return (msLookupHashTable(self, key));
  }
  
  // Remove one item from hash table
  int hashTableObj_remove(hashTableObj *self, const char *key)
  {
    return (msRemoveHashTable(self, key));
  }
  
  // Clear all items in hash table (to NULL)
  void hashTableObj_clear(hashTableObj *self)
  {
    msFreeHashItems(self);
    initHashTable(self);
  }
  
  // Return the next key or first key if previousKey == NULL
  char *hashTableObj_nextKey(hashTableObj *self, const char *previousKey)
  {
    return ((char *)msNextKeyFromHashTable(self, previousKey));
  }
  
  resultObj *resultObj_new()
  {
    resultObj *r = (resultObj *) msSmallMalloc(sizeof(resultObj));
    r->tileindex = -1;
    r->shapeindex = -1;
    r->resultindex = -1;
    return r;
  }
  
  /**********************************************************************
   * class extensions clusterObj
   **********************************************************************/
  
  int clusterObj_updateFromString(clusterObj *self, char *snippet)
  {
    return msUpdateClusterFromString(self, snippet);
  }
  
  char *clusterObj_convertToString(clusterObj *self)
  {
    return msWriteClusterToString(self);
  }
  
  int clusterObj_setGroup(clusterObj *self, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->group);
      return MS_SUCCESS;
    } else return msLoadExpressionString(&self->group, string);
  }
  
  char *clusterObj_getGroupString(clusterObj *self)
  {
    return msGetExpressionString(&(self->group));
  }
  
  int clusterObj_setFilter(clusterObj *self, char *string)
  {
    if (!string || strlen(string) == 0) {
      freeExpression(&self->filter);
      return MS_SUCCESS;
    } else return msLoadExpressionString(&self->filter, string);
  }
  
  char *clusterObj_getFilterString(clusterObj *self)
  {
    return msGetExpressionString(&(self->filter));
  }
  
  outputFormatObj* outputFormatObj_new(const char *driver, char *name)
  {
    outputFormatObj *format;
  
    format = msCreateDefaultOutputFormat(NULL, driver, name);
  
    /* in the case of unsupported formats, msCreateDefaultOutputFormat
       should return NULL */
    if (!format) {
      msSetError(MS_MISCERR, "Unsupported format driver: %s",
                 "outputFormatObj()", driver);
      return NULL;
    }
  
    msInitializeRendererVTable(format);
  
    /* Else, continue */
    format->refcount++;
    format->inmapfile = MS_TRUE;
  
    return format;
  }
  
  void  outputFormatObj_destroy(outputFormatObj* self)
  {
    if ( --self->refcount < 1 )
      msFreeOutputFormat( self );
  }
  
  imageObj *symbolObj_getImage(symbolObj *self, outputFormatObj *input_format)
  {
    imageObj *image = NULL;
    outputFormatObj *format = NULL;
    rendererVTableObj *renderer = NULL;
  
    if (self->type != MS_SYMBOL_PIXMAP) {
      msSetError(MS_SYMERR, "Can't return image from non-pixmap symbol",
                 "getImage()");
      return NULL;
    }
  
    if (input_format) {
      format = input_format;
    } else {
      format = msCreateDefaultOutputFormat(NULL, "GD/GIF", "gdgif");
      if (format == NULL)
        format = msCreateDefaultOutputFormat(NULL, "GD/PNG", "gdpng");
  
      if (format)
        msInitializeRendererVTable(format);
    }
  
    if (format == NULL) {
      msSetError(MS_IMGERR, "Could not create output format",
                 "getImage()");
      return NULL;
    }
  
    renderer = format->vtable;
    msPreloadImageSymbol(renderer, self);
    if (self->pixmap_buffer) {
      image = msImageCreate(self->pixmap_buffer->width, self->pixmap_buffer->height, format, NULL, NULL,
                            MS_DEFAULT_RESOLUTION, MS_DEFAULT_RESOLUTION, NULL);
      renderer->mergeRasterBuffer(image, self->pixmap_buffer, 1.0, 0, 0, 0, 0,
                                  self->pixmap_buffer->width, self->pixmap_buffer->height);
    }
  
    return image;
  }
  
  int symbolObj_setImage(symbolObj *self, imageObj *image)
  {
    rendererVTableObj *renderer = NULL;
  
    renderer = image->format->vtable;
  
    if (self->pixmap_buffer) {
      msFreeRasterBuffer(self->pixmap_buffer);
      free(self->pixmap_buffer);
    }
  
    self->pixmap_buffer = (rasterBufferObj*)malloc(sizeof(rasterBufferObj));
    if (!self->pixmap_buffer) {
      msSetError(MS_MEMERR, NULL, "setImage()");
      return MS_FAILURE;
    }
    self->type = MS_SYMBOL_PIXMAP;
    renderer->getRasterBufferCopy(image, self->pixmap_buffer);
  
    return MS_SUCCESS;
  }
  