1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  MapServer
5  * Purpose:  Implementation of most layerObj functions.
6  * Author:   Steve Lime and the MapServer team.
7  *
8  ******************************************************************************
9  * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies of this Software or works derived from this Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "mapserver.h"
31 #include "maptime.h"
32 #include "mapogcfilter.h"
33 #include "mapthread.h"
34 #include "mapfile.h"
35 
36 #include "mapparser.h"
37 
38 #include <assert.h>
39 
40 static int populateVirtualTable(layerVTableObj *vtable);
41 
42 /*
43 ** Iteminfo is a layer parameter that holds information necessary to retrieve an individual item for
44 ** a particular source. It is an array built from a list of items. The type of iteminfo will vary by
45 ** source. For shapefiles and OGR it is simply an array of integers where each value is an index for
46 ** the item. For SDE it's a ESRI specific type that contains index and column type information. Two
47 ** helper functions below initialize and free that structure member which is used locally by layer
48 ** specific functions.
49 */
msLayerInitItemInfo(layerObj * layer)50 int msLayerInitItemInfo(layerObj *layer)
51 {
52   if ( ! layer->vtable) {
53     int rv =  msInitializeVirtualTable(layer);
54     if (rv != MS_SUCCESS)
55       return rv;
56   }
57   return layer->vtable->LayerInitItemInfo(layer);
58 }
59 
msLayerFreeItemInfo(layerObj * layer)60 void msLayerFreeItemInfo(layerObj *layer)
61 {
62   if ( ! layer->vtable) {
63     int rv =  msInitializeVirtualTable(layer);
64     if (rv != MS_SUCCESS)
65       return;
66   }
67   layer->vtable->LayerFreeItemInfo(layer);
68 
69   /*
70    * Layer expressions with attribute binding hold a numeric index pointing
71    * to an iteminfo (node->tokenval.bindval.index). If iteminfo changes,
72    * an expression may be no longer valid. (#5161)
73    */
74   msLayerFreeExpressions(layer);
75 }
76 
msLayerRestoreFromScaletokens(layerObj * layer)77 int msLayerRestoreFromScaletokens(layerObj *layer)
78 {
79   if(!layer->scaletokens || !layer->orig_st) {
80     return MS_SUCCESS;
81   }
82   if(layer->orig_st->data) {
83     msFree(layer->data);
84     layer->data = layer->orig_st->data;
85   }
86   if(layer->orig_st->tileindex) {
87     msFree(layer->tileindex);
88     layer->tileindex = layer->orig_st->tileindex;
89   }
90   if(layer->orig_st->tileitem) {
91     msFree(layer->tileitem);
92     layer->tileitem = layer->orig_st->tileitem;
93   }
94   if(layer->orig_st->filter) {
95     msLoadExpressionString(&(layer->filter),layer->orig_st->filter);
96     msFree(layer->orig_st->filter);
97   }
98   if(layer->orig_st->filteritem) {
99     msFree(layer->filteritem);
100     layer->filteritem = layer->orig_st->filteritem;
101   }
102   if(layer->orig_st->n_processing) {
103     int i;
104     for(i=0;i<layer->orig_st->n_processing;i++) {
105       msFree(layer->processing[layer->orig_st->processing_idx[i]]);
106       layer->processing[layer->orig_st->processing_idx[i]] = layer->orig_st->processing[i];
107     }
108     msFree(layer->orig_st->processing);
109     msFree(layer->orig_st->processing_idx);
110   }
111   msFree(layer->orig_st);
112   layer->orig_st = NULL;
113   return MS_SUCCESS;
114 }
115 
116 #define check_st_alloc(l) if(!l->orig_st) l->orig_st=msSmallCalloc(1,sizeof(originalScaleTokenStrings));
msLayerApplyScaletokens(layerObj * layer,double scale)117 int msLayerApplyScaletokens(layerObj *layer, double scale)
118 {
119   int i,p;
120   if(!layer->scaletokens) {
121     return MS_SUCCESS;
122   }
123   msLayerRestoreFromScaletokens(layer);
124   for(i=0;i<layer->numscaletokens;i++) {
125     scaleTokenObj *st = &layer->scaletokens[i];
126     scaleTokenEntryObj *ste = NULL;
127     if(scale<=0) {
128        ste = &(st->tokens[0]);
129       /* no scale defined, use first entry */
130     } else {
131       int tokenindex=0;
132       while(tokenindex<st->n_entries) {
133         ste = &(st->tokens[tokenindex]);
134         if(scale < ste->maxscale && scale >= ste->minscale) break; /* current token is the correct one */
135         tokenindex++;
136         ste = NULL;
137       }
138     }
139     assert(ste);
140     if(layer->data && strstr(layer->data,st->name)) {
141       if(layer->debug >= MS_DEBUGLEVEL_DEBUG) {
142         msDebug("replacing scaletoken (%s) with (%s) in layer->data (%s) for scale=%f\n",
143                 st->name,ste->value,layer->name,scale);
144       }
145       check_st_alloc(layer);
146       layer->orig_st->data = layer->data;
147       layer->data = msStrdup(layer->data);
148       layer->data = msReplaceSubstring(layer->data,st->name,ste->value);
149     }
150     if(layer->tileindex && strstr(layer->tileindex,st->name)) {
151       if(layer->debug >= MS_DEBUGLEVEL_DEBUG) {
152         msDebug("replacing scaletoken (%s) with (%s) in layer->tileindex (%s) for scale=%f\n",
153                 st->name,ste->value,layer->name,scale);
154       }
155       check_st_alloc(layer);
156       layer->orig_st->tileindex = layer->tileindex;
157       layer->tileindex = msStrdup(layer->tileindex);
158       layer->tileindex = msReplaceSubstring(layer->tileindex,st->name,ste->value);
159     }
160     if(layer->tileitem && strstr(layer->tileitem,st->name)) {
161       if(layer->debug >= MS_DEBUGLEVEL_DEBUG) {
162         msDebug("replacing scaletoken (%s) with (%s) in layer->tileitem (%s) for scale=%f\n",
163                 st->name,ste->value,layer->name,scale);
164       }
165       check_st_alloc(layer);
166       layer->orig_st->tileitem = layer->tileitem;
167       layer->tileitem = msStrdup(layer->tileitem);
168       layer->tileitem = msReplaceSubstring(layer->tileitem,st->name,ste->value);
169     }
170     if(layer->filteritem && strstr(layer->filteritem,st->name)) {
171       if(layer->debug >= MS_DEBUGLEVEL_DEBUG) {
172         msDebug("replacing scaletoken (%s) with (%s) in layer->filteritem (%s) for scale=%f\n",
173                 st->name,ste->value,layer->name,scale);
174       }
175       check_st_alloc(layer);
176       layer->orig_st->filteritem = layer->filteritem;
177       layer->filteritem = msStrdup(layer->filteritem);
178       layer->filteritem = msReplaceSubstring(layer->filteritem,st->name,ste->value);
179     }
180     if(layer->filter.string && strstr(layer->filter.string,st->name)) {
181       char *tmpval;
182       if(layer->debug >= MS_DEBUGLEVEL_DEBUG) {
183         msDebug("replacing scaletoken (%s) with (%s) in layer->filter (%s) for scale=%f\n",
184                 st->name,ste->value,layer->name,scale);
185       }
186       check_st_alloc(layer);
187       layer->orig_st->filter = msStrdup(layer->filter.string);
188       tmpval = msStrdup(layer->filter.string);
189       tmpval = msReplaceSubstring(tmpval,st->name,ste->value);
190       if(msLoadExpressionString(&(layer->filter),tmpval) == -1) return(MS_FAILURE); /* msLoadExpressionString() cleans up previously allocated expression */
191       msFree(tmpval);
192     }
193     for(p=0;p<layer->numprocessing;p++) {
194       if(strstr(layer->processing[p],st->name)) {
195         check_st_alloc(layer);
196         layer->orig_st->n_processing++;
197         layer->orig_st->processing = msSmallRealloc(layer->orig_st->processing, layer->orig_st->n_processing * sizeof(char*));
198         layer->orig_st->processing_idx = msSmallRealloc(layer->orig_st->processing_idx, layer->orig_st->n_processing * sizeof(int));
199         layer->orig_st->processing[layer->orig_st->n_processing-1] = layer->processing[p];
200         layer->orig_st->processing_idx[layer->orig_st->n_processing-1] = p;
201         layer->processing[p] = msStrdup(layer->processing[p]);
202         layer->processing[p] = msReplaceSubstring(layer->processing[p],st->name,ste->value);
203       }
204     }
205 
206   }
207   return MS_SUCCESS;
208 }
209 
210 
211 /*
212 ** Does exactly what it implies, readies a layer for processing.
213 */
msLayerOpen(layerObj * layer)214 int msLayerOpen(layerObj *layer)
215 {
216   int rv;
217 
218   /* RFC-86 Scale dependant token replacements*/
219   rv = msLayerApplyScaletokens(layer,(layer->map)?layer->map->scaledenom:-1);
220   if (rv != MS_SUCCESS) return rv;
221 
222   /* RFC-69 clustering support */
223   if (layer->cluster.region)
224     return msClusterLayerOpen(layer);
225 
226   if(layer->features && layer->connectiontype != MS_GRATICULE )
227     layer->connectiontype = MS_INLINE;
228 
229   if(layer->tileindex && layer->connectiontype == MS_SHAPEFILE)
230     layer->connectiontype = MS_TILED_SHAPEFILE;
231 
232   if(layer->type == MS_LAYER_RASTER && layer->connectiontype != MS_WMS
233       && layer->connectiontype != MS_KERNELDENSITY)
234     layer->connectiontype = MS_RASTER;
235 
236   if ( ! layer->vtable) {
237     rv =  msInitializeVirtualTable(layer);
238     if (rv != MS_SUCCESS)
239       return rv;
240   }
241   return layer->vtable->LayerOpen(layer);
242 }
243 
244 /*
245 ** Returns MS_TRUE if layer has been opened using msLayerOpen(), MS_FALSE otherwise
246 */
msLayerIsOpen(layerObj * layer)247 int msLayerIsOpen(layerObj *layer)
248 {
249   if ( ! layer->vtable) {
250     int rv =  msInitializeVirtualTable(layer);
251     if (rv != MS_SUCCESS)
252       return rv;
253   }
254   return layer->vtable->LayerIsOpen(layer);
255 }
256 
257 /*
258 ** Returns MS_TRUE is a layer supports the common expression/filter syntax (RFC 64) and MS_FALSE otherwise.
259 */
msLayerSupportsCommonFilters(layerObj * layer)260 int msLayerSupportsCommonFilters(layerObj *layer)
261 {
262   if ( ! layer->vtable) {
263     int rv =  msInitializeVirtualTable(layer);
264     if (rv != MS_SUCCESS)
265       return rv;
266   }
267   return layer->vtable->LayerSupportsCommonFilters(layer);
268 }
269 
msLayerTranslateFilter(layerObj * layer,expressionObj * filter,char * filteritem)270 int msLayerTranslateFilter(layerObj *layer, expressionObj *filter, char *filteritem)
271 {
272   if (!layer->vtable) {
273     int rv =  msInitializeVirtualTable(layer);
274     if (rv != MS_SUCCESS)
275       return rv;
276   }
277   return layer->vtable->LayerTranslateFilter(layer, filter, filteritem);
278 }
279 
280 /*
281 ** Performs a spatial, and optionally an attribute based feature search. The function basically
282 ** prepares things so that candidate features can be accessed by query or drawing functions. For
283 ** OGR and shapefiles this sets an internal bit vector that indicates whether a particular feature
284 ** is to processed. For SDE it executes an SQL statement on the SDE server. Once run the msLayerNextShape
285 ** function should be called to actually access the shapes.
286 **
287 ** Note that for shapefiles we apply any maxfeatures constraint at this point. That may be the only
288 ** connection type where this is feasible.
289 */
msLayerWhichShapes(layerObj * layer,rectObj rect,int isQuery)290 int msLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery)
291 {
292   if(!msLayerSupportsCommonFilters(layer))
293     msLayerTranslateFilter(layer, &layer->filter, layer->filteritem);
294 
295   if ( ! layer->vtable) {
296     int rv =  msInitializeVirtualTable(layer);
297     if (rv != MS_SUCCESS)
298       return rv;
299   }
300   return layer->vtable->LayerWhichShapes(layer, rect, isQuery);
301 }
302 
303 /*
304 ** Called after msWhichShapes has been called to actually retrieve shapes within a given area
305 ** and matching a vendor specific filter (i.e. layer FILTER attribute).
306 **
307 ** Shapefiles: NULL shapes (shapes with attributes but NO vertices are skipped)
308 */
msLayerNextShape(layerObj * layer,shapeObj * shape)309 int msLayerNextShape(layerObj *layer, shapeObj *shape)
310 {
311   int rv, filter_passed;
312 
313   if ( ! layer->vtable) {
314     rv =  msInitializeVirtualTable(layer);
315     if (rv != MS_SUCCESS)
316       return rv;
317   }
318 
319 #ifdef USE_V8_MAPSCRIPT
320   /* we need to force the GetItems for the geomtransform attributes */
321   if(!layer->items &&
322      layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION &&
323      strstr(layer->_geomtransform.string, "javascript"))
324       msLayerGetItems(layer);
325 #endif
326 
327   /* At the end of switch case (default -> break; -> return MS_FAILURE),
328    * was following TODO ITEM:
329    *
330    * TO DO! This is where dynamic joins will happen. Joined attributes will be
331    * tagged on to the main attributes with the naming scheme [join name].[item name].
332    * We need to leverage the iteminfo (I think) at this point
333    */
334 
335   /* RFC 91: MapServer-based filtering is done at a more general level. */
336   do {
337     rv = layer->vtable->LayerNextShape(layer, shape);
338     if(rv != MS_SUCCESS) return rv;
339 
340     filter_passed = MS_TRUE;  /* By default accept ANY shape */
341 
342     /* attributes need to be iconv'd to UTF-8 before any filter logic is applied */
343     if(layer->encoding) {
344       rv = msLayerEncodeShapeAttributes(layer,shape);
345       if(rv != MS_SUCCESS)
346         return rv;
347     }
348 
349     // if(layer->numitems > 0 && layer->iteminfo) {
350       filter_passed = msEvalExpression(layer, shape, &(layer->filter), layer->filteritemindex);
351     // }
352 
353     if(!filter_passed) msFreeShape(shape);
354   } while(!filter_passed);
355 
356   /* RFC89 Apply Layer GeomTransform */
357   if(layer->_geomtransform.type != MS_GEOMTRANSFORM_NONE && rv == MS_SUCCESS) {
358     rv = msGeomTransformShape(layer->map, layer, shape);
359     if(rv != MS_SUCCESS)
360       return rv;
361   }
362 
363 
364   return rv;
365 }
366 
367 /*
368 ** Used to retrieve a shape from a result set by index. Result sets are created by the various
369 ** msQueryBy...() functions. The index is assigned by the data source.
370 */
371 /* int msLayerResultsGetShape(layerObj *layer, shapeObj *shape, int tile, long record)
372 {
373   if ( ! layer->vtable) {
374     int rv =  msInitializeVirtualTable(layer);
375     if (rv != MS_SUCCESS)
376       return rv;
377   }
378 
379   return layer->vtable->LayerResultsGetShape(layer, shape, tile, record);
380 } */
381 
382 /*
383 ** Used to retrieve a shape by index. All data sources must be capable of random access using
384 ** a record number(s) of some sort.
385 */
msLayerGetShape(layerObj * layer,shapeObj * shape,resultObj * record)386 int msLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record)
387 {
388   int rv;
389 
390   if( ! layer->vtable) {
391     rv =  msInitializeVirtualTable(layer);
392     if(rv != MS_SUCCESS)
393       return rv;
394   }
395 
396   /*
397   ** TODO: This is where dynamic joins could happen. Joined attributes would be
398   ** tagged on to the main attributes with the naming scheme [join name].[item name].
399   */
400 
401   rv = layer->vtable->LayerGetShape(layer, shape, record);
402   if(rv != MS_SUCCESS)
403     return rv;
404 
405   /* RFC89 Apply Layer GeomTransform */
406   if(layer->_geomtransform.type != MS_GEOMTRANSFORM_NONE && rv == MS_SUCCESS) {
407     rv = msGeomTransformShape(layer->map, layer, shape);
408     if(rv != MS_SUCCESS)
409       return rv;
410   }
411 
412   if(layer->encoding) {
413     rv = msLayerEncodeShapeAttributes(layer,shape);
414     if(rv != MS_SUCCESS)
415       return rv;
416   }
417 
418   return rv;
419 }
420 
421 /*
422 ** Returns the number of shapes that match the potential filter and extent.
423  * rectProjection is the projection in which rect is expressed, or can be NULL if
424  * rect should be considered in the layer projection.
425  * This should be equivalent to calling msLayerWhichShapes() and counting the
426  * number of shapes returned by msLayerNextShape(), honouring layer->maxfeatures
427  * limitation if layer->maxfeatures>=0, and honouring layer->startindex if
428  * layer->startindex >= 1 and paging is enabled.
429  * Returns -1 in case of failure.
430  */
msLayerGetShapeCount(layerObj * layer,rectObj rect,projectionObj * rectProjection)431 int msLayerGetShapeCount(layerObj *layer, rectObj rect, projectionObj *rectProjection)
432 {
433   int rv;
434 
435   if( ! layer->vtable) {
436     rv = msInitializeVirtualTable(layer);
437     if(rv != MS_SUCCESS)
438       return -1;
439   }
440 
441   return layer->vtable->LayerGetShapeCount(layer, rect, rectProjection);
442 }
443 
444 
445 /*
446 ** Closes resources used by a particular layer.
447 */
msLayerClose(layerObj * layer)448 void msLayerClose(layerObj *layer)
449 {
450   /* no need for items once the layer is closed */
451   msLayerFreeItemInfo(layer);
452   if(layer->items) {
453     msFreeCharArray(layer->items, layer->numitems);
454     layer->items = NULL;
455     layer->numitems = 0;
456   }
457 
458   /* clear out items used as part of expressions (bug #2702) -- what about the layer filter? */
459   msLayerFreeExpressions(layer);
460 
461   if (layer->vtable) {
462     layer->vtable->LayerClose(layer);
463   }
464   msLayerRestoreFromScaletokens(layer);
465 }
466 
467 /*
468 ** Clear out items used as part of expressions.
469 */
msLayerFreeExpressions(layerObj * layer)470 void msLayerFreeExpressions(layerObj *layer)
471 {
472   int i,j,k;
473 
474   msFreeExpressionTokens(&(layer->filter));
475   msFreeExpressionTokens(&(layer->cluster.group));
476   msFreeExpressionTokens(&(layer->cluster.filter));
477   for(i=0; i<layer->numclasses; i++) {
478     msFreeExpressionTokens(&(layer->class[i]->expression));
479     msFreeExpressionTokens(&(layer->class[i]->text));
480     for(j=0; j<layer->class[i]->numstyles; j++)
481       msFreeExpressionTokens(&(layer->class[i]->styles[j]->_geomtransform));
482     for(k=0; k<layer->class[i]->numlabels; k++) {
483       msFreeExpressionTokens(&(layer->class[i]->labels[k]->expression));
484       msFreeExpressionTokens(&(layer->class[i]->labels[k]->text));
485     }
486   }
487 }
488 
489 /*
490 ** Retrieves a list of attributes available for this layer. Most sources also set the iteminfo array
491 ** at this point. This function is used when processing query results to expose attributes to query
492 ** templates. At that point all attributes are fair game.
493 */
msLayerGetItems(layerObj * layer)494 int msLayerGetItems(layerObj *layer)
495 {
496   const char *itemNames;
497   /* clean up any previously allocated instances */
498   msLayerFreeItemInfo(layer);
499   if(layer->items) {
500     msFreeCharArray(layer->items, layer->numitems);
501     layer->items = NULL;
502     layer->numitems = 0;
503   }
504 
505   if ( ! layer->vtable) {
506     int rv =  msInitializeVirtualTable(layer);
507     if (rv != MS_SUCCESS)
508       return rv;
509   }
510 
511   /* At the end of switch case (default -> break; -> return MS_FAILURE),
512    * was following TODO ITEM:
513    */
514   /* TO DO! Need to add any joined itemd on to the core layer items, one long list!  */
515   itemNames = msLayerGetProcessingKey( layer, "ITEMS" );
516   if (itemNames) {
517     layer->items = msStringSplit(itemNames, ',', &layer->numitems);
518     /* populate the iteminfo array */
519     return (msLayerInitItemInfo(layer));
520   } else
521     return layer->vtable->LayerGetItems(layer);
522 }
523 
524 /*
525 ** Returns extent of spatial coverage for a layer.
526 **
527 ** If layer->extent is set then this value is used, otherwise the
528 ** driver-specific implementation is called (this can be expensive).
529 **
530 ** If layer is not already opened then it is opened and closed (so this
531 ** function can be called on both opened or closed layers).
532 **
533 ** Returns MS_SUCCESS/MS_FAILURE.
534 */
msLayerGetExtent(layerObj * layer,rectObj * extent)535 int msLayerGetExtent(layerObj *layer, rectObj *extent)
536 {
537   int need_to_close = MS_FALSE, status = MS_SUCCESS;
538 
539   if (MS_VALID_EXTENT(layer->extent)) {
540     *extent = layer->extent;
541     return MS_SUCCESS;
542   }
543 
544   if (!msLayerIsOpen(layer)) {
545     if (msLayerOpen(layer) != MS_SUCCESS)
546       return MS_FAILURE;
547     need_to_close = MS_TRUE;
548   }
549 
550   if ( ! layer->vtable) {
551     int rv =  msInitializeVirtualTable(layer);
552     if (rv != MS_SUCCESS) {
553       if (need_to_close)
554         msLayerClose(layer);
555       return rv;
556     }
557   }
558   status = layer->vtable->LayerGetExtent(layer, extent);
559 
560   if (need_to_close)
561     msLayerClose(layer);
562 
563   return(status);
564 }
565 
msLayerGetItemIndex(layerObj * layer,char * item)566 int msLayerGetItemIndex(layerObj *layer, char *item)
567 {
568   int i;
569 
570   for(i=0; i<layer->numitems; i++) {
571     if(strcasecmp(layer->items[i], item) == 0) return(i);
572   }
573 
574   return -1; /* item not found */
575 }
576 
string2list(char ** list,int * listsize,char * string)577 static int string2list(char **list, int *listsize, char *string)
578 {
579   int i;
580 
581   for(i=0; i<(*listsize); i++) {
582     if(strcasecmp(list[i], string) == 0) {
583       /* printf("string2list (duplicate): %s %d\n", string, i); */
584       return(i);
585     }
586   }
587 
588   list[i] = msStrdup(string);
589   (*listsize)++;
590 
591   /* printf("string2list: %s %d\n", string, i); */
592 
593   return(i);
594 }
595 
596 extern int msyylex(void);
597 extern int msyylex_destroy(void);
598 
599 extern int msyystate;
600 extern char *msyystring; /* string to tokenize */
601 
602 extern double msyynumber; /* token containers */
603 extern char *msyystring_buffer;
604 
msExpressionTokenToString(int token)605 const char *msExpressionTokenToString(int token) {
606   switch(token) {
607     case '(': return "(";
608     case ')': return ")";
609     case ',': return ",";
610     case '+': return "+";
611     case '-': return "-";
612     case '/': return "/";
613     case '*': return "*";
614     case '%': return "%";
615 
616     case MS_TOKEN_LOGICAL_AND: return " and ";
617     case MS_TOKEN_LOGICAL_OR: return " or ";
618     case MS_TOKEN_LOGICAL_NOT: return " not ";
619 
620     case MS_TOKEN_COMPARISON_EQ: return " = ";
621     case MS_TOKEN_COMPARISON_NE: return " != ";
622     case MS_TOKEN_COMPARISON_GT: return " > ";
623     case MS_TOKEN_COMPARISON_GE: return " >= ";
624     case MS_TOKEN_COMPARISON_LT: return " < ";
625     case MS_TOKEN_COMPARISON_LE: return " <= ";
626     case MS_TOKEN_COMPARISON_IEQ: return "";
627     case MS_TOKEN_COMPARISON_RE: return " ~ ";
628     case MS_TOKEN_COMPARISON_IRE: return " ~* ";
629     case MS_TOKEN_COMPARISON_IN: return " in ";
630     case MS_TOKEN_COMPARISON_LIKE: return " like ";
631 
632     case MS_TOKEN_COMPARISON_INTERSECTS: return "intersects";
633     case MS_TOKEN_COMPARISON_DISJOINT: return "disjoint";
634     case MS_TOKEN_COMPARISON_TOUCHES: return "touches";
635     case MS_TOKEN_COMPARISON_OVERLAPS: return "overlaps";
636     case MS_TOKEN_COMPARISON_CROSSES: return "crosses";
637     case MS_TOKEN_COMPARISON_WITHIN: return "within";
638     case MS_TOKEN_COMPARISON_CONTAINS: return "contains";
639     case MS_TOKEN_COMPARISON_EQUALS: return "equals";
640     case MS_TOKEN_COMPARISON_BEYOND: return "beyond";
641     case MS_TOKEN_COMPARISON_DWITHIN: return "dwithin";
642 
643     case MS_TOKEN_FUNCTION_LENGTH: return "length";
644     case MS_TOKEN_FUNCTION_TOSTRING: return "tostring";
645     case MS_TOKEN_FUNCTION_COMMIFY: return "commify";
646     case MS_TOKEN_FUNCTION_AREA: return "area";
647     case MS_TOKEN_FUNCTION_ROUND: return "round";
648     case MS_TOKEN_FUNCTION_BUFFER: return "buffer";
649     case MS_TOKEN_FUNCTION_DIFFERENCE: return "difference";
650     case MS_TOKEN_FUNCTION_SIMPLIFY: return "simplify";
651     // case MS_TOKEN_FUNCTION_SIMPLIFYPT:
652     case MS_TOKEN_FUNCTION_GENERALIZE: return "generalize";
653     default: return NULL;
654   }
655 }
656 
msTokenizeExpression(expressionObj * expression,char ** list,int * listsize)657 int msTokenizeExpression(expressionObj *expression, char **list, int *listsize)
658 {
659   tokenListNodeObjPtr node;
660   int token;
661 
662   /* TODO: make sure the constants can't somehow reference invalid expression types */
663   /* if(expression->type != MS_EXPRESSION && expression->type != MS_GEOMTRANSFORM_EXPRESSION) return MS_SUCCESS; */
664 
665   msAcquireLock(TLOCK_PARSER);
666   msyystate = MS_TOKENIZE_EXPRESSION;
667   msyystring = expression->string; /* the thing we're tokenizing */
668 
669   while((token = msyylex()) != 0) { /* keep processing tokens until the end of the string (\0) */
670 
671     if((node = (tokenListNodeObjPtr) malloc(sizeof(tokenListNodeObj))) == NULL) {
672       msSetError(MS_MEMERR, NULL, "msTokenizeExpression()");
673       goto parse_error;
674     }
675 
676     node->tokensrc = NULL;
677 
678     node->tailifhead = NULL;
679     node->next = NULL;
680 
681     switch(token) {
682       case MS_TOKEN_LITERAL_BOOLEAN:
683       case MS_TOKEN_LITERAL_NUMBER:
684         node->token = token;
685         node->tokenval.dblval = msyynumber;
686         break;
687       case MS_TOKEN_LITERAL_STRING:
688         node->token = token;
689         node->tokenval.strval = msStrdup(msyystring_buffer);
690         break;
691       case MS_TOKEN_LITERAL_TIME:
692         node->tokensrc = msStrdup(msyystring_buffer);
693         node->token = token;
694         msTimeInit(&(node->tokenval.tmval));
695         if(msParseTime(msyystring_buffer, &(node->tokenval.tmval)) != MS_TRUE) {
696           msSetError(MS_PARSEERR, "Parsing time value failed.", "msTokenizeExpression()");
697           free(node);
698           goto parse_error;
699         }
700         break;
701       case MS_TOKEN_BINDING_DOUBLE: /* we've encountered an attribute (binding) reference */
702       case MS_TOKEN_BINDING_INTEGER:
703       case MS_TOKEN_BINDING_STRING:
704       case MS_TOKEN_BINDING_TIME:
705         node->token = token; /* binding type */
706         node->tokenval.bindval.item = msStrdup(msyystring_buffer);
707         if(list) node->tokenval.bindval.index = string2list(list, listsize, msyystring_buffer);
708         break;
709       case MS_TOKEN_BINDING_SHAPE:
710         node->token = token;
711         break;
712       case MS_TOKEN_BINDING_MAP_CELLSIZE:
713         node->token = token;
714         break;
715       case MS_TOKEN_BINDING_DATA_CELLSIZE:
716         node->token = token;
717         break;
718       case MS_TOKEN_FUNCTION_FROMTEXT: /* we want to process a shape from WKT once and not for every feature being evaluated */
719         if((token = msyylex()) != 40) { /* ( */
720           msSetError(MS_PARSEERR, "Parsing fromText function failed.", "msTokenizeExpression()");
721           free(node);
722           goto parse_error;
723         }
724 
725         if((token = msyylex()) != MS_TOKEN_LITERAL_STRING) {
726           msSetError(MS_PARSEERR, "Parsing fromText function failed.", "msTokenizeExpression()");
727           free(node);
728           goto parse_error;
729         }
730 
731         node->token = MS_TOKEN_LITERAL_SHAPE;
732         node->tokenval.shpval = msShapeFromWKT(msyystring_buffer);
733 
734         if(!node->tokenval.shpval) {
735           msSetError(MS_PARSEERR, "Parsing fromText function failed, WKT processing failed.", "msTokenizeExpression()");
736           free(node);
737           goto parse_error;
738         }
739 
740         /* todo: perhaps process optional args (e.g. projection) */
741 
742         if((token = msyylex()) != 41) { /* ) */
743           msSetError(MS_PARSEERR, "Parsing fromText function failed.", "msTokenizeExpression()");
744           msFreeShape(node->tokenval.shpval);
745           free(node->tokenval.shpval);
746           free(node);
747           goto parse_error;
748         }
749         break;
750       default:
751         node->token = token; /* for everything else */
752         break;
753     }
754 
755     /* add node to token list */
756     if(expression->tokens == NULL) {
757       expression->tokens = node;
758     } else {
759       if(expression->tokens->tailifhead != NULL) /* this should never be NULL, but just in case */
760         expression->tokens->tailifhead->next = node; /* put the node at the end of the list */
761     }
762 
763     /* repoint the head of the list to the end  - our new element
764        this causes a loop if we are at the head, be careful not to
765        walk in a loop */
766     expression->tokens->tailifhead = node;
767   }
768 
769   expression->curtoken = expression->tokens; /* point at the first token */
770 
771   msReleaseLock(TLOCK_PARSER);
772   return MS_SUCCESS;
773 
774 parse_error:
775   msReleaseLock(TLOCK_PARSER);
776   return MS_FAILURE;
777 }
778 
779 /*
780 ** This function builds a list of items necessary to draw or query a particular layer by
781 ** examining the contents of the various xxxxitem parameters and expressions. That list is
782 ** then used to set the iteminfo variable.
783 */
msLayerWhichItems(layerObj * layer,int get_all,const char * metadata)784 int msLayerWhichItems(layerObj *layer, int get_all, const char *metadata)
785 {
786   int i, j, k, l, rv;
787   int nt=0;
788 
789   if (!layer->vtable) {
790     rv =  msInitializeVirtualTable(layer);
791     if (rv != MS_SUCCESS) return rv;
792   }
793 
794   /* Cleanup any previous item selection */
795   msLayerFreeItemInfo(layer);
796   if(layer->items) {
797     msFreeCharArray(layer->items, layer->numitems);
798     layer->items = NULL;
799     layer->numitems = 0;
800   }
801 
802   /*
803   ** need a count of potential items/attributes needed
804   */
805 
806   /* layer level counts */
807   layer->classitemindex = -1;
808   layer->filteritemindex = -1;
809   layer->styleitemindex = -1;
810   layer->labelitemindex = -1;
811   layer->utfitemindex = -1;
812 
813   if(layer->classitem) nt++;
814   if(layer->filteritem) nt++;
815   if(layer->styleitem &&
816      (strcasecmp(layer->styleitem, "AUTO") != 0) &&
817      (strncasecmp(layer->styleitem, "javascript://", 13) != 0)) nt++;
818 
819   if(layer->filter.type == MS_EXPRESSION)
820     nt += msCountChars(layer->filter.string, '[');
821 
822   if(layer->cluster.group.type == MS_EXPRESSION)
823     nt += msCountChars(layer->cluster.group.string, '[');
824 
825   if(layer->cluster.filter.type == MS_EXPRESSION)
826     nt += msCountChars(layer->cluster.filter.string, '[');
827 
828   if(layer->labelitem) nt++;
829   if(layer->utfitem) nt++;
830 
831   if(layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION)
832     msTokenizeExpression(&layer->_geomtransform, layer->items, &(layer->numitems));
833 
834   /* class level counts */
835   for(i=0; i<layer->numclasses; i++) {
836 
837     for(j=0; j<layer->class[i]->numstyles; j++) {
838       if(layer->class[i]->styles[j]->rangeitem) nt++;
839       nt += layer->class[i]->styles[j]->numbindings;
840       if(layer->class[i]->styles[j]->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION)
841         nt += msCountChars(layer->class[i]->styles[j]->_geomtransform.string, '[');
842       for(k=0; k<MS_STYLE_BINDING_LENGTH; k++) {
843         if (layer->class[i]->styles[j]->exprBindings[k].type == MS_EXPRESSION)
844         {
845           nt += msCountChars(layer->class[i]->styles[j]->exprBindings[k].string, '[');
846         }
847       }
848     }
849 
850     if(layer->class[i]->expression.type == MS_EXPRESSION)
851       nt += msCountChars(layer->class[i]->expression.string, '[');
852 
853     for(l=0; l<layer->class[i]->numlabels; l++) {
854       nt += layer->class[i]->labels[l]->numbindings;
855       for(j=0; j<layer->class[i]->labels[l]->numstyles; j++) {
856         if(layer->class[i]->labels[l]->styles[j]->rangeitem) nt++;
857         nt += layer->class[i]->labels[l]->styles[j]->numbindings;
858         if(layer->class[i]->labels[l]->styles[j]->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION)
859           nt += msCountChars(layer->class[i]->labels[l]->styles[j]->_geomtransform.string, '[');
860       }
861       for(k=0; k<MS_LABEL_BINDING_LENGTH; k++) {
862         if (layer->class[i]->labels[l]->exprBindings[k].type == MS_EXPRESSION)
863         {
864           nt += msCountChars(layer->class[i]->labels[l]->exprBindings[k].string, '[');
865         }
866       }
867 
868       if(layer->class[i]->labels[l]->expression.type == MS_EXPRESSION)
869         nt += msCountChars(layer->class[i]->labels[l]->expression.string, '[');
870       if(layer->class[i]->labels[l]->text.type == MS_EXPRESSION || (layer->class[i]->labels[l]->text.string && strchr(layer->class[i]->labels[l]->text.string,'[') != NULL && strchr(layer->class[i]->labels[l]->text.string,']') != NULL))
871         nt += msCountChars(layer->class[i]->labels[l]->text.string, '[');
872     }
873 
874     if(layer->class[i]->text.type == MS_EXPRESSION || (layer->class[i]->text.string && strchr(layer->class[i]->text.string,'[') != NULL && strchr(layer->class[i]->text.string,']') != NULL))
875       nt += msCountChars(layer->class[i]->text.string, '[');
876   }
877 
878   /* utfgrid count */
879   if(layer->utfdata.type == MS_EXPRESSION || (layer->utfdata.string && strchr(layer->utfdata.string,'[') != NULL && strchr(layer->utfdata.string,']') != NULL))
880     nt += msCountChars(layer->utfdata.string, '[');
881 
882   /*
883   ** allocate space for the item list (worse case size)
884   */
885 
886   /* always retrieve all items in some cases */
887   if(layer->connectiontype == MS_INLINE || get_all == MS_TRUE ||
888       (layer->map->outputformat && layer->map->outputformat->renderer == MS_RENDER_WITH_KML)) {
889     rv = msLayerGetItems(layer);
890     if(nt > 0) /* need to realloc the array to accept the possible new items*/
891       layer->items = (char **)msSmallRealloc(layer->items, sizeof(char *)*(layer->numitems + nt));
892   } else {
893     rv = layer->vtable->LayerCreateItems(layer, nt);
894   }
895   if(rv != MS_SUCCESS)
896     return rv;
897 
898   /*
899   ** build layer item list, compute item indexes for explicity item references (e.g. classitem) or item bindings
900   */
901 
902   /* layer items */
903   if(layer->classitem) layer->classitemindex = string2list(layer->items, &(layer->numitems), layer->classitem);
904   if(layer->filteritem) layer->filteritemindex = string2list(layer->items, &(layer->numitems), layer->filteritem);
905   if(layer->styleitem && (strcasecmp(layer->styleitem, "AUTO") != 0) && (strncasecmp(layer->styleitem, "javascript://",13) != 0))
906     layer->styleitemindex = string2list(layer->items, &(layer->numitems), layer->styleitem);
907   if(layer->labelitem) layer->labelitemindex = string2list(layer->items, &(layer->numitems), layer->labelitem);
908   if(layer->utfitem) layer->utfitemindex = string2list(layer->items, &(layer->numitems), layer->utfitem);
909 
910   /* layer classes */
911   for(i=0; i<layer->numclasses; i++) {
912 
913     if(layer->class[i]->expression.type == MS_EXPRESSION) /* class expression */
914       msTokenizeExpression(&(layer->class[i]->expression), layer->items, &(layer->numitems));
915 
916     /* class styles (items, bindings, geomtransform) */
917     for(j=0; j<layer->class[i]->numstyles; j++) {
918       if(layer->class[i]->styles[j]->rangeitem)
919         layer->class[i]->styles[j]->rangeitemindex = string2list(layer->items, &(layer->numitems), layer->class[i]->styles[j]->rangeitem);
920       for(k=0; k<MS_STYLE_BINDING_LENGTH; k++) {
921         if(layer->class[i]->styles[j]->bindings[k].item)
922           layer->class[i]->styles[j]->bindings[k].index = string2list(layer->items, &(layer->numitems), layer->class[i]->styles[j]->bindings[k].item);
923         if (layer->class[i]->styles[j]->exprBindings[k].type == MS_EXPRESSION)
924         {
925           msTokenizeExpression(
926               &(layer->class[i]->styles[j]->exprBindings[k]),
927               layer->items, &(layer->numitems));
928         }
929       }
930       if(layer->class[i]->styles[j]->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION)
931         msTokenizeExpression(&(layer->class[i]->styles[j]->_geomtransform), layer->items, &(layer->numitems));
932     }
933 
934     /* class labels and label styles (items, bindings, geomtransform) */
935     for(l=0; l<layer->class[i]->numlabels; l++) {
936       for(j=0; j<layer->class[i]->labels[l]->numstyles; j++) {
937         if(layer->class[i]->labels[l]->styles[j]->rangeitem)
938           layer->class[i]->labels[l]->styles[j]->rangeitemindex = string2list(layer->items, &(layer->numitems), layer->class[i]->labels[l]->styles[j]->rangeitem);
939         for(k=0; k<MS_STYLE_BINDING_LENGTH; k++) {
940           if(layer->class[i]->labels[l]->styles[j]->bindings[k].item)
941             layer->class[i]->labels[l]->styles[j]->bindings[k].index = string2list(layer->items, &(layer->numitems), layer->class[i]->labels[l]->styles[j]->bindings[k].item);
942           if(layer->class[i]->labels[l]->styles[j]->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION)
943             msTokenizeExpression(&(layer->class[i]->labels[l]->styles[j]->_geomtransform), layer->items, &(layer->numitems));
944         }
945       }
946       for(k=0; k<MS_LABEL_BINDING_LENGTH; k++) {
947         if(layer->class[i]->labels[l]->bindings[k].item)
948           layer->class[i]->labels[l]->bindings[k].index = string2list(layer->items, &(layer->numitems), layer->class[i]->labels[l]->bindings[k].item);
949         if (layer->class[i]->labels[l]->exprBindings[k].type == MS_EXPRESSION)
950         {
951           msTokenizeExpression(
952               &(layer->class[i]->labels[l]->exprBindings[k]),
953               layer->items, &(layer->numitems));
954         }
955       }
956 
957        /* label expression */
958       if(layer->class[i]->labels[l]->expression.type == MS_EXPRESSION) msTokenizeExpression(&(layer->class[i]->labels[l]->expression), layer->items, &(layer->numitems));
959 
960       /* label text */
961       if(layer->class[i]->labels[l]->text.type == MS_EXPRESSION || (layer->class[i]->labels[l]->text.string && strchr(layer->class[i]->labels[l]->text.string,'[') != NULL && strchr(layer->class[i]->labels[l]->text.string,']') != NULL))
962         msTokenizeExpression(&(layer->class[i]->labels[l]->text), layer->items, &(layer->numitems));
963     }
964 
965     /* class text */
966     if(layer->class[i]->text.type == MS_EXPRESSION || (layer->class[i]->text.string && strchr(layer->class[i]->text.string,'[') != NULL && strchr(layer->class[i]->text.string,']') != NULL))
967       msTokenizeExpression(&(layer->class[i]->text), layer->items, &(layer->numitems));
968   }
969 
970   /* layer filter */
971   if(layer->filter.type == MS_EXPRESSION) msTokenizeExpression(&(layer->filter), layer->items, &(layer->numitems));
972 
973   /* cluster expressions */
974   if(layer->cluster.group.type == MS_EXPRESSION) msTokenizeExpression(&(layer->cluster.group), layer->items, &(layer->numitems));
975   if(layer->cluster.filter.type == MS_EXPRESSION) msTokenizeExpression(&(layer->cluster.filter), layer->items, &(layer->numitems));
976 
977   /* utfdata */
978   if(layer->utfdata.type == MS_EXPRESSION || (layer->utfdata.string && strchr(layer->utfdata.string,'[') != NULL && strchr(layer->utfdata.string,']') != NULL)) {
979     msTokenizeExpression(&(layer->utfdata), layer->items, &(layer->numitems));
980   }
981 
982   if(metadata) {
983     char **tokens;
984     int n = 0;
985     int j;
986     int bFound = 0;
987 
988     tokens = msStringSplit(metadata, ',', &n);
989     if(tokens) {
990       for(i=0; i<n; i++) {
991         bFound = 0;
992         for(j=0; j<layer->numitems; j++) {
993           if(strcmp(tokens[i], layer->items[j]) == 0) {
994             bFound = 1;
995             break;
996           }
997         }
998 
999         if(!bFound) {
1000           layer->numitems++;
1001           layer->items =  (char **)msSmallRealloc(layer->items, sizeof(char *)*(layer->numitems));
1002           layer->items[layer->numitems-1] = msStrdup(tokens[i]);
1003         }
1004       }
1005       msFreeCharArray(tokens, n);
1006     }
1007   }
1008 
1009   /* populate the iteminfo array */
1010   if(layer->numitems == 0)
1011     return(MS_SUCCESS);
1012 
1013   return(msLayerInitItemInfo(layer));
1014 }
1015 
1016 /*
1017 ** A helper function to set the items to be retrieved with a particular shape. Unused at the moment but will be used
1018 ** from within MapScript. Should not need modification.
1019 */
msLayerSetItems(layerObj * layer,char ** items,int numitems)1020 int msLayerSetItems(layerObj *layer, char **items, int numitems)
1021 {
1022   int i;
1023   /* Cleanup any previous item selection */
1024   msLayerFreeItemInfo(layer);
1025   if(layer->items) {
1026     msFreeCharArray(layer->items, layer->numitems);
1027     layer->items = NULL;
1028     layer->numitems = 0;
1029   }
1030 
1031   /* now allocate and set the layer item parameters  */
1032   layer->items = (char **)malloc(sizeof(char *)*numitems);
1033   MS_CHECK_ALLOC(layer->items, sizeof(char *)*numitems, MS_FAILURE);
1034 
1035   for(i=0; i<numitems; i++)
1036     layer->items[i] = msStrdup(items[i]);
1037   layer->numitems = numitems;
1038 
1039   /* populate the iteminfo array */
1040   return(msLayerInitItemInfo(layer));
1041 
1042   return(MS_SUCCESS);
1043 }
1044 
1045 /*
1046 ** Fills a classObj with style info from the specified shape.  This is used
1047 ** with STYLEITEM AUTO when rendering shapes.
1048 ** For optimal results, this should be called immediately after
1049 ** GetNextShape() or GetShape() so that the shape doesn't have to be read
1050 ** twice.
1051 **
1052 */
msLayerGetAutoStyle(mapObj * map,layerObj * layer,classObj * c,shapeObj * shape)1053 int msLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, shapeObj* shape)
1054 {
1055   if ( ! layer->vtable) {
1056     int rv =  msInitializeVirtualTable(layer);
1057     if (rv != MS_SUCCESS)
1058       return rv;
1059   }
1060   return layer->vtable->LayerGetAutoStyle(map, layer, c, shape);
1061 }
1062 
1063 /*
1064 ** Fills a classObj with style info from the specified attribute.  This is used
1065 ** with STYLEITEM "attribute" when rendering shapes.
1066 **
1067 */
msLayerGetFeatureStyle(mapObj * map,layerObj * layer,classObj * c,shapeObj * shape)1068 int msLayerGetFeatureStyle(mapObj *map, layerObj *layer, classObj *c, shapeObj* shape)
1069 {
1070   char* stylestring = NULL;
1071   if (layer->styleitem && layer->styleitemindex >=0) {
1072     stylestring = msStrdup(shape->values[layer->styleitemindex]);
1073   }
1074   else if (strncasecmp(layer->styleitem,"javascript://",13) == 0) {
1075 #ifdef USE_V8_MAPSCRIPT
1076     char *filename = layer->styleitem+13;
1077 
1078     if (!map->v8context) {
1079       msV8CreateContext(map);
1080       if (!map->v8context)
1081       {
1082         msSetError(MS_V8ERR, "Unable to create v8 context.", "msLayerGetFeatureStyle()");
1083         return MS_FAILURE;
1084       }
1085     }
1086 
1087     if (*filename == '\0') {
1088       msSetError(MS_V8ERR, "Invalid javascript filename: \"%s\".", "msLayerGetFeatureStyle()", layer->styleitem);
1089       return MS_FAILURE;
1090     }
1091 
1092     stylestring = msV8GetFeatureStyle(map, filename, layer, shape);
1093 #else
1094       msSetError(MS_V8ERR, "V8 Javascript support is not available.", "msLayerGetFeatureStyle()");
1095       return MS_FAILURE;
1096 #endif
1097   }
1098   else { /* unknown styleitem */
1099     return MS_FAILURE;
1100   }
1101 
1102   /* try to find out the current style format */
1103   if (!stylestring)
1104     return MS_FAILURE;
1105 
1106   if (strncasecmp(stylestring,"style",5) == 0) {
1107     resetClassStyle(c);
1108     c->layer = layer;
1109     if (msMaybeAllocateClassStyle(c, 0)) {
1110       free(stylestring);
1111       return(MS_FAILURE);
1112     }
1113 
1114     msUpdateStyleFromString(c->styles[0], stylestring, MS_FALSE);
1115     if(c->styles[0]->symbolname) {
1116       if((c->styles[0]->symbol =  msGetSymbolIndex(&(map->symbolset), c->styles[0]->symbolname, MS_TRUE)) == -1) {
1117         msSetError(MS_MISCERR, "Undefined symbol \"%s\" in class of layer %s.", "msLayerGetFeatureStyle()",
1118                    c->styles[0]->symbolname, layer->name);
1119         free(stylestring);
1120         return MS_FAILURE;
1121       }
1122     }
1123   } else if (strncasecmp(stylestring,"class",5) == 0) {
1124     if (strcasestr(stylestring, " style ") != NULL) {
1125       /* reset style if stylestring contains style definitions */
1126       resetClassStyle(c);
1127       c->layer = layer;
1128     }
1129     msUpdateClassFromString(c, stylestring, MS_FALSE);
1130   } else if (strncasecmp(stylestring,"pen",3) == 0 || strncasecmp(stylestring,"brush",5) == 0 ||
1131              strncasecmp(stylestring,"symbol",6) == 0 || strncasecmp(stylestring,"label",5) == 0) {
1132     msOGRUpdateStyleFromString(map, layer, c, stylestring);
1133   } else {
1134     resetClassStyle(c);
1135   }
1136 
1137   free(stylestring);
1138   return MS_SUCCESS;
1139 }
1140 
1141 
1142 /*
1143 Returns the number of inline feature of a layer
1144 */
msLayerGetNumFeatures(layerObj * layer)1145 int msLayerGetNumFeatures(layerObj *layer)
1146 {
1147     int need_to_close = MS_FALSE, result = -1;
1148 
1149     if (!msLayerIsOpen(layer)) {
1150         if (msLayerOpen(layer) != MS_SUCCESS)
1151             return result;
1152         need_to_close = MS_TRUE;
1153     }
1154 
1155     if (!layer->vtable) {
1156         int rv = msInitializeVirtualTable(layer);
1157         if (rv != MS_SUCCESS)
1158             return result;
1159     }
1160 
1161     result = layer->vtable->LayerGetNumFeatures(layer);
1162 
1163     if (need_to_close)
1164         msLayerClose(layer);
1165 
1166     return(result);
1167 }
1168 
1169 void
msLayerSetProcessingKey(layerObj * layer,const char * key,const char * value)1170 msLayerSetProcessingKey( layerObj *layer, const char *key, const char *value)
1171 
1172 {
1173   int len = strlen(key);
1174   int i;
1175   char *directive = NULL;
1176 
1177   if( value != NULL ) {
1178     directive = (char *) msSmallMalloc(strlen(key)+strlen(value)+2);
1179     sprintf( directive, "%s=%s", key, value );
1180   }
1181 
1182   for( i = 0; i < layer->numprocessing; i++ ) {
1183     if( strncasecmp( key, layer->processing[i], len ) == 0
1184         && layer->processing[i][len] == '=' ) {
1185       free( layer->processing[i] );
1186 
1187       /*
1188       ** Either replace the existing entry with a new one or
1189       ** clear the entry.
1190       */
1191       if( directive != NULL )
1192         layer->processing[i] = directive;
1193       else {
1194         layer->processing[i] = layer->processing[layer->numprocessing-1];
1195         layer->processing[layer->numprocessing-1] = NULL;
1196         layer->numprocessing--;
1197       }
1198       return;
1199     }
1200   }
1201 
1202   /* otherwise add the directive at the end. */
1203 
1204   if( directive != NULL ) {
1205     msLayerAddProcessing( layer, directive );
1206     free( directive );
1207   }
1208 }
1209 
msLayerSubstituteProcessing(layerObj * layer,const char * from,const char * to)1210 void msLayerSubstituteProcessing( layerObj *layer, const char *from, const char *to ) {
1211   int i;
1212   for( i = 0; i < layer->numprocessing; i++ ) {
1213     layer->processing[i] = msCaseReplaceSubstring(layer->processing[i], from, to);
1214   }
1215 }
1216 
msLayerAddProcessing(layerObj * layer,const char * directive)1217 void msLayerAddProcessing( layerObj *layer, const char *directive )
1218 
1219 {
1220   layer->numprocessing++;
1221   if( layer->numprocessing == 1 )
1222     layer->processing = (char **) msSmallMalloc(2*sizeof(char *));
1223   else
1224     layer->processing = (char **) msSmallRealloc(layer->processing, sizeof(char*) * (layer->numprocessing+1) );
1225   layer->processing[layer->numprocessing-1] = msStrdup(directive);
1226   layer->processing[layer->numprocessing] = NULL;
1227 }
1228 
msLayerGetProcessing(layerObj * layer,int proc_index)1229 char *msLayerGetProcessing( layerObj *layer, int proc_index)
1230 {
1231   if (proc_index < 0 || proc_index >= layer->numprocessing) {
1232     msSetError(MS_CHILDERR, "Invalid processing index.", "msLayerGetProcessing()");
1233     return NULL;
1234   } else {
1235     return layer->processing[proc_index];
1236   }
1237 }
1238 
msLayerGetProcessingKey(layerObj * layer,const char * key)1239 char *msLayerGetProcessingKey( layerObj *layer, const char *key )
1240 {
1241   int i, len = strlen(key);
1242 
1243   for( i = 0; i < layer->numprocessing; i++ ) {
1244     if( strncasecmp(layer->processing[i],key,len) == 0
1245         && layer->processing[i][len] == '=' )
1246       return layer->processing[i] + len + 1;
1247   }
1248 
1249   return NULL;
1250 }
1251 
1252 
1253 /************************************************************************/
1254 /*                       msLayerGetMaxFeaturesToDraw                    */
1255 /*                                                                      */
1256 /*      Check to see if maxfeaturestodraw is set as a metadata or an    */
1257 /*      output format option. Used for vector layers to limit the       */
1258 /*      number of fatures rendered.                                     */
1259 /************************************************************************/
msLayerGetMaxFeaturesToDraw(layerObj * layer,outputFormatObj * format)1260 int msLayerGetMaxFeaturesToDraw(layerObj *layer, outputFormatObj *format)
1261 {
1262   int nMaxFeatures = -1;
1263   const char *pszTmp = NULL;
1264   if (layer) {
1265     nMaxFeatures = layer->maxfeatures;
1266     pszTmp = msLookupHashTable(&layer->metadata, "maxfeaturestodraw");
1267     if (pszTmp)
1268       nMaxFeatures = atoi(pszTmp);
1269     else {
1270       pszTmp = msLookupHashTable(&layer->map->web.metadata, "maxfeaturestodraw");
1271       if (pszTmp)
1272         nMaxFeatures = atoi(pszTmp);
1273     }
1274   }
1275   if(format) {
1276     if (nMaxFeatures < 0)
1277       nMaxFeatures = atoi(msGetOutputFormatOption( format, "maxfeaturestodraw", "-1"));
1278   }
1279 
1280   return nMaxFeatures;
1281 
1282 }
msLayerClearProcessing(layerObj * layer)1283 int msLayerClearProcessing( layerObj *layer )
1284 {
1285   if (layer->numprocessing > 0) {
1286     msFreeCharArray( layer->processing, layer->numprocessing );
1287     layer->processing = NULL;
1288     layer->numprocessing = 0;
1289   }
1290   return layer->numprocessing;
1291 }
1292 
1293 
1294 int
makeTimeFilter(layerObj * lp,const char * timestring,const char * timefield,const int addtimebacktics)1295 makeTimeFilter(layerObj *lp,
1296                const char *timestring,
1297                const char *timefield,
1298                const int addtimebacktics)
1299 {
1300 
1301   char **atimes, **tokens = NULL;
1302   int numtimes,i, ntmp = 0;
1303   char *pszBuffer = NULL;
1304   int bOnlyExistingFilter = 0;
1305 
1306   if (!lp || !timestring || !timefield)
1307     return MS_FALSE;
1308 
1309   /* parse the time string. We support dicrete times (eg 2004-09-21),  */
1310   /* multiple times (2004-09-21, 2004-09-22, ...) */
1311   /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */
1312 
1313   if (strstr(timestring, ",") == NULL &&
1314       strstr(timestring, "/") == NULL) { /* discrete time */
1315     /*
1316     if(lp->filteritem) free(lp->filteritem);
1317     lp->filteritem = msStrdup(timefield);
1318     if (&lp->filter)
1319       msFreeExpression(&lp->filter);
1320     */
1321 
1322     /* if the filter is set and it's a sting type, concatenate it with
1323        the time. If not just free it */
1324      if (lp->filter.string && lp->filter.type == MS_STRING) {
1325       pszBuffer = msStringConcatenate(pszBuffer, "((");
1326       pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string);
1327       pszBuffer = msStringConcatenate(pszBuffer, ") and ");
1328     } else {
1329       msFreeExpression(&lp->filter);
1330     }
1331 
1332     pszBuffer = msStringConcatenate(pszBuffer, "(");
1333     if (addtimebacktics)
1334       pszBuffer = msStringConcatenate(pszBuffer,  "`");
1335 
1336     if (addtimebacktics)
1337       pszBuffer = msStringConcatenate(pszBuffer, "[");
1338     pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield);
1339     if (addtimebacktics)
1340       pszBuffer = msStringConcatenate(pszBuffer, "]");
1341     if (addtimebacktics)
1342       pszBuffer = msStringConcatenate(pszBuffer,  "`");
1343 
1344 
1345     pszBuffer = msStringConcatenate(pszBuffer, " = ");
1346     if (addtimebacktics)
1347       pszBuffer = msStringConcatenate(pszBuffer,  "`");
1348     else
1349       pszBuffer = msStringConcatenate(pszBuffer,  "'");
1350 
1351     pszBuffer = msStringConcatenate(pszBuffer, (char *)timestring);
1352     if (addtimebacktics)
1353       pszBuffer = msStringConcatenate(pszBuffer,  "`");
1354     else
1355       pszBuffer = msStringConcatenate(pszBuffer,  "'");
1356 
1357     pszBuffer = msStringConcatenate(pszBuffer, ")");
1358 
1359     /* if there was a filter, It was concatenate with an And ans should be closed*/
1360     if(lp->filter.string && lp->filter.type == MS_STRING) {
1361       pszBuffer = msStringConcatenate(pszBuffer, ")");
1362     }
1363 
1364     msLoadExpressionString(&lp->filter, pszBuffer);
1365 
1366     if (pszBuffer)
1367       msFree(pszBuffer);
1368 
1369     return MS_TRUE;
1370   }
1371 
1372   atimes = msStringSplit(timestring, ',', &numtimes);
1373   if (atimes == NULL || numtimes < 1) {
1374     msFreeCharArray(atimes,numtimes);
1375     return MS_FALSE;
1376   }
1377 
1378   if (lp->filter.string && lp->filter.type == MS_STRING) {
1379     pszBuffer = msStringConcatenate(pszBuffer, "((");
1380     pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string);
1381     pszBuffer = msStringConcatenate(pszBuffer, ") and ");
1382     /*this flag is used to indicate that the buffer contains only the
1383       existing filter. It is set to 0 when time filter parts are
1384       added to the buffer */
1385     bOnlyExistingFilter = 1;
1386   } else
1387     msFreeExpression(&lp->filter);
1388 
1389   /* check to see if we have ranges by parsing the first entry */
1390   tokens = msStringSplit(atimes[0],  '/', &ntmp);
1391   if (ntmp == 2) { /* ranges */
1392     msFreeCharArray(tokens, ntmp);
1393     for (i=0; i<numtimes; i++) {
1394       tokens = msStringSplit(atimes[i],  '/', &ntmp);
1395       if (ntmp == 2) {
1396         if (pszBuffer && strlen(pszBuffer) > 0 && bOnlyExistingFilter == 0)
1397           pszBuffer = msStringConcatenate(pszBuffer, " OR ");
1398         else
1399           pszBuffer = msStringConcatenate(pszBuffer, "(");
1400 
1401         bOnlyExistingFilter = 0;
1402 
1403         pszBuffer = msStringConcatenate(pszBuffer, "(");
1404         if (addtimebacktics)
1405           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1406 
1407         if (addtimebacktics)
1408           pszBuffer = msStringConcatenate(pszBuffer, "[");
1409         pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield);
1410         if (addtimebacktics)
1411           pszBuffer = msStringConcatenate(pszBuffer, "]");
1412 
1413         if (addtimebacktics)
1414           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1415 
1416         pszBuffer = msStringConcatenate(pszBuffer, " >= ");
1417         if (addtimebacktics)
1418           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1419         else
1420           pszBuffer = msStringConcatenate(pszBuffer,  "'");
1421 
1422         pszBuffer = msStringConcatenate(pszBuffer, tokens[0]);
1423         if (addtimebacktics)
1424           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1425         else
1426           pszBuffer = msStringConcatenate(pszBuffer,  "'");
1427         pszBuffer = msStringConcatenate(pszBuffer, " AND ");
1428 
1429         if (addtimebacktics)
1430           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1431 
1432         if (addtimebacktics)
1433           pszBuffer = msStringConcatenate(pszBuffer, "[");
1434         pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield);
1435         if (addtimebacktics)
1436           pszBuffer = msStringConcatenate(pszBuffer, "]");
1437         if (addtimebacktics)
1438           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1439 
1440         pszBuffer = msStringConcatenate(pszBuffer, " <= ");
1441 
1442         if (addtimebacktics)
1443           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1444         else
1445           pszBuffer = msStringConcatenate(pszBuffer,  "'");
1446         pszBuffer = msStringConcatenate(pszBuffer, tokens[1]);
1447         if (addtimebacktics)
1448           pszBuffer = msStringConcatenate(pszBuffer,  "`");
1449         else
1450           pszBuffer = msStringConcatenate(pszBuffer,  "'");
1451         pszBuffer = msStringConcatenate(pszBuffer, ")");
1452       }
1453 
1454       msFreeCharArray(tokens, ntmp);
1455     }
1456     if (pszBuffer && strlen(pszBuffer) > 0 && bOnlyExistingFilter == 0)
1457       pszBuffer = msStringConcatenate(pszBuffer, ")");
1458   } else if (ntmp == 1) { /* multiple times */
1459     msFreeCharArray(tokens, ntmp);
1460     pszBuffer = msStringConcatenate(pszBuffer, "(");
1461     for (i=0; i<numtimes; i++) {
1462       if (i > 0)
1463         pszBuffer = msStringConcatenate(pszBuffer, " OR ");
1464 
1465       pszBuffer = msStringConcatenate(pszBuffer, "(");
1466       if (addtimebacktics)
1467         pszBuffer = msStringConcatenate(pszBuffer, "`");
1468 
1469       if (addtimebacktics)
1470         pszBuffer = msStringConcatenate(pszBuffer, "[");
1471       pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield);
1472       if (addtimebacktics)
1473         pszBuffer = msStringConcatenate(pszBuffer, "]");
1474 
1475       if (addtimebacktics)
1476         pszBuffer = msStringConcatenate(pszBuffer, "`");
1477 
1478       pszBuffer = msStringConcatenate(pszBuffer, " = ");
1479 
1480       if (addtimebacktics)
1481         pszBuffer = msStringConcatenate(pszBuffer, "`");
1482       else
1483         pszBuffer = msStringConcatenate(pszBuffer,  "'");
1484       pszBuffer = msStringConcatenate(pszBuffer, atimes[i]);
1485       if (addtimebacktics)
1486         pszBuffer = msStringConcatenate(pszBuffer,  "`");
1487       else
1488         pszBuffer = msStringConcatenate(pszBuffer,  "'");
1489       pszBuffer = msStringConcatenate(pszBuffer, ")");
1490     }
1491     pszBuffer = msStringConcatenate(pszBuffer, ")");
1492   } else {
1493     msFreeCharArray(tokens, ntmp);
1494     msFreeCharArray(atimes, numtimes);
1495     msFree(pszBuffer);
1496     return MS_FALSE;
1497   }
1498 
1499   msFreeCharArray(atimes, numtimes);
1500 
1501   /* load the string to the filter */
1502   if (pszBuffer && strlen(pszBuffer) > 0) {
1503     if(lp->filter.string && lp->filter.type == MS_STRING)
1504       pszBuffer = msStringConcatenate(pszBuffer, ")");
1505     /*
1506     if(lp->filteritem)
1507       free(lp->filteritem);
1508     lp->filteritem = msStrdup(timefield);
1509     */
1510 
1511     msLoadExpressionString(&lp->filter, pszBuffer);
1512 
1513   }
1514   msFree(pszBuffer);
1515   return MS_TRUE;
1516 }
1517 
1518 /**
1519   set the filter parameter for a time filter
1520 **/
1521 
msLayerSetTimeFilter(layerObj * lp,const char * timestring,const char * timefield)1522 int msLayerSetTimeFilter(layerObj *lp, const char *timestring,
1523                          const char *timefield)
1524 {
1525   if ( ! lp->vtable) {
1526     int rv =  msInitializeVirtualTable(lp);
1527     if (rv != MS_SUCCESS)
1528       return rv;
1529   }
1530   return lp->vtable->LayerSetTimeFilter(lp, timestring, timefield);
1531 }
1532 
1533 int
msLayerMakeBackticsTimeFilter(layerObj * lp,const char * timestring,const char * timefield)1534 msLayerMakeBackticsTimeFilter(layerObj *lp, const char *timestring,
1535                               const char *timefield)
1536 {
1537   return makeTimeFilter(lp, timestring, timefield, MS_TRUE);
1538 }
1539 
1540 int
msLayerMakePlainTimeFilter(layerObj * lp,const char * timestring,const char * timefield)1541 msLayerMakePlainTimeFilter(layerObj *lp, const char *timestring,
1542                            const char *timefield)
1543 {
1544   return makeTimeFilter(lp, timestring, timefield, MS_FALSE);
1545 }
1546 
1547 
1548 /*
1549  * Dummies / default actions for layers
1550  */
LayerDefaultInitItemInfo(layerObj * layer)1551 int LayerDefaultInitItemInfo(layerObj *layer)
1552 {
1553   return MS_SUCCESS;
1554 }
1555 
LayerDefaultFreeItemInfo(layerObj * layer)1556 void LayerDefaultFreeItemInfo(layerObj *layer)
1557 {
1558   return;
1559 }
1560 
LayerDefaultOpen(layerObj * layer)1561 int LayerDefaultOpen(layerObj *layer)
1562 {
1563   return MS_FAILURE;
1564 }
1565 
LayerDefaultIsOpen(layerObj * layer)1566 int LayerDefaultIsOpen(layerObj *layer)
1567 {
1568   return MS_FALSE;
1569 }
1570 
LayerDefaultWhichShapes(layerObj * layer,rectObj rect,int isQuery)1571 int LayerDefaultWhichShapes(layerObj *layer, rectObj rect, int isQuery)
1572 {
1573   return MS_SUCCESS;
1574 }
1575 
LayerDefaultNextShape(layerObj * layer,shapeObj * shape)1576 int LayerDefaultNextShape(layerObj *layer, shapeObj *shape)
1577 {
1578   return MS_FAILURE;
1579 }
1580 
LayerDefaultGetShape(layerObj * layer,shapeObj * shape,resultObj * record)1581 int LayerDefaultGetShape(layerObj *layer, shapeObj *shape, resultObj *record)
1582 {
1583   return MS_FAILURE;
1584 }
1585 
LayerDefaultGetShapeCount(layerObj * layer,rectObj rect,projectionObj * rectProjection)1586 int LayerDefaultGetShapeCount(layerObj *layer, rectObj rect, projectionObj *rectProjection)
1587 {
1588   int status;
1589   shapeObj shape, searchshape;
1590   int nShapeCount = 0;
1591   rectObj searchrect = rect;
1592   reprojectionObj* reprojector = NULL;
1593 
1594   msInitShape(&searchshape);
1595   msRectToPolygon(searchrect, &searchshape);
1596 
1597   if( rectProjection != NULL )
1598   {
1599     if(layer->project && msProjectionsDiffer(&(layer->projection), rectProjection))
1600       msProjectRect(rectProjection, &(layer->projection), &searchrect); /* project the searchrect to source coords */
1601     else
1602       layer->project = MS_FALSE;
1603   }
1604 
1605   status = msLayerWhichShapes(layer, searchrect, MS_TRUE) ;
1606   if( status == MS_FAILURE )
1607   {
1608     msFreeShape(&searchshape);
1609     return -1;
1610   }
1611   else if( status == MS_DONE )
1612   {
1613     msFreeShape(&searchshape);
1614     return 0;
1615   }
1616 
1617   msInitShape(&shape);
1618   while((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS)
1619   {
1620     if( rectProjection != NULL )
1621     {
1622       if(layer->project && msProjectionsDiffer(&(layer->projection), rectProjection))
1623       {
1624         if( reprojector == NULL )
1625             reprojector = msProjectCreateReprojector(&(layer->projection), rectProjection);
1626         if( reprojector )
1627             msProjectShapeEx(reprojector, &shape);
1628       }
1629       else
1630         layer->project = MS_FALSE;
1631 
1632       if(msRectContained(&shape.bounds, &rect) == MS_TRUE) { /* if the whole shape is in, don't intersect */
1633         status = MS_TRUE;
1634       } else {
1635         switch(shape.type) { /* make sure shape actually intersects the qrect (ADD FUNCTIONS SPECIFIC TO RECTOBJ) */
1636           case MS_SHAPE_POINT:
1637             status = msIntersectMultipointPolygon(&shape, &searchshape);
1638             break;
1639           case MS_SHAPE_LINE:
1640             status = msIntersectPolylinePolygon(&shape, &searchshape);
1641             break;
1642           case MS_SHAPE_POLYGON:
1643             status = msIntersectPolygons(&shape, &searchshape);
1644             break;
1645           default:
1646             break;
1647         }
1648       }
1649     }
1650     else
1651       status = MS_TRUE;
1652 
1653     if( status == MS_TRUE )
1654       nShapeCount++ ;
1655     msFreeShape(&shape);
1656     if(layer->maxfeatures > 0 && layer->maxfeatures == nShapeCount)
1657       break;
1658   }
1659 
1660   msFreeShape(&searchshape);
1661   msProjectDestroyReprojector(reprojector);
1662 
1663   return nShapeCount;
1664 }
1665 
LayerDefaultClose(layerObj * layer)1666 int LayerDefaultClose(layerObj *layer)
1667 {
1668   return MS_SUCCESS;
1669 }
1670 
LayerDefaultGetItems(layerObj * layer)1671 int LayerDefaultGetItems(layerObj *layer)
1672 {
1673   return MS_SUCCESS; /* returning no items is legit */
1674 }
1675 
1676 int
msLayerApplyCondSQLFilterToLayer(FilterEncodingNode * psNode,mapObj * map,int iLayerIndex)1677 msLayerApplyCondSQLFilterToLayer(FilterEncodingNode *psNode, mapObj *map,
1678                                  int iLayerIndex)
1679 {
1680   return FLTLayerApplyCondSQLFilterToLayer(psNode, map, iLayerIndex);
1681 }
1682 
msLayerSupportsPaging(layerObj * layer)1683 int msLayerSupportsPaging(layerObj *layer)
1684 {
1685   if (layer &&
1686       ((layer->connectiontype == MS_ORACLESPATIAL) ||
1687        (layer->connectiontype == MS_POSTGIS)) )
1688     return MS_TRUE;
1689 
1690   return MS_FALSE;
1691 }
1692 
1693 int msLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, int iLayerIndex);
1694 
1695 /*
1696  * msLayerSupportsSorting()
1697  *
1698  * Returns MS_TRUE if the layer supports sorting/ordering.
1699  */
msLayerSupportsSorting(layerObj * layer)1700 int msLayerSupportsSorting(layerObj *layer)
1701 {
1702   if (layer && (
1703     (layer->connectiontype == MS_OGR) || (layer->connectiontype == MS_POSTGIS) || (layer->connectiontype == MS_ORACLESPATIAL) || ((layer->connectiontype == MS_PLUGIN) && (strstr(layer->plugin_library,"msplugin_oracle") != NULL)) || ((layer->connectiontype == MS_PLUGIN) && (strstr(layer->plugin_library,"msplugin_mssql2008") != NULL))
1704                )
1705      )
1706     return MS_TRUE;
1707 
1708   return MS_FALSE;
1709 }
1710 
1711 /*
1712  * msLayerSetSort()
1713  *
1714  * Copy the sortBy clause passed as an argument into the layer sortBy member.
1715  */
msLayerSetSort(layerObj * layer,const sortByClause * sortBy)1716 void msLayerSetSort(layerObj *layer, const sortByClause* sortBy)
1717 {
1718   int i;
1719   for(i=0;i<layer->sortBy.nProperties;i++)
1720     msFree(layer->sortBy.properties[i].item);
1721   msFree(layer->sortBy.properties);
1722 
1723   layer->sortBy.nProperties = sortBy->nProperties;
1724   layer->sortBy.properties = (sortByProperties*) msSmallMalloc(sortBy->nProperties * sizeof(sortByProperties));
1725   for(i=0;i<layer->sortBy.nProperties;i++) {
1726     layer->sortBy.properties[i].item = msStrdup(sortBy->properties[i].item);
1727     layer->sortBy.properties[i].sortOrder = sortBy->properties[i].sortOrder;
1728   }
1729  }
1730 
1731 /*
1732  * msLayerBuildSQLOrderBy()
1733  *
1734  * Returns the content of a SQL ORDER BY clause from the sortBy member of
1735  * the layer. The string does not contain the "ORDER BY" keywords itself.
1736  */
msLayerBuildSQLOrderBy(layerObj * layer)1737 char* msLayerBuildSQLOrderBy(layerObj *layer)
1738 {
1739   char* strOrderBy = NULL;
1740   if( layer->sortBy.nProperties > 0 ) {
1741     int i;
1742     for(i=0;i<layer->sortBy.nProperties;i++) {
1743       char* escaped = msLayerEscapePropertyName(layer, layer->sortBy.properties[i].item);
1744       if( i > 0 )
1745         strOrderBy = msStringConcatenate(strOrderBy, ", ");
1746       strOrderBy = msStringConcatenate(strOrderBy, escaped);
1747       if( layer->sortBy.properties[i].sortOrder == SORT_DESC )
1748         strOrderBy = msStringConcatenate(strOrderBy, " DESC");
1749       msFree(escaped);
1750     }
1751   }
1752   return strOrderBy;
1753 }
1754 
1755 int
msLayerApplyPlainFilterToLayer(FilterEncodingNode * psNode,mapObj * map,int iLayerIndex)1756 msLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, int iLayerIndex)
1757 {
1758   return FLTLayerApplyPlainFilterToLayer(psNode, map, iLayerIndex);
1759 }
1760 
msLayerGetPaging(layerObj * layer)1761 int msLayerGetPaging(layerObj *layer)
1762 {
1763   if ( ! layer->vtable) {
1764     int rv =  msInitializeVirtualTable(layer);
1765     if (rv != MS_SUCCESS) {
1766       msSetError(MS_MISCERR, "Unable to initialize virtual table", "msLayerGetPaging()");
1767       return MS_FAILURE;
1768     }
1769   }
1770   return layer->vtable->LayerGetPaging(layer);
1771 }
1772 
msLayerEnablePaging(layerObj * layer,int value)1773 void msLayerEnablePaging(layerObj *layer, int value)
1774 {
1775   if ( ! layer->vtable) {
1776     int rv =  msInitializeVirtualTable(layer);
1777     if (rv != MS_SUCCESS) {
1778       msSetError(MS_MISCERR, "Unable to initialize virtual table", "msLayerEnablePaging()");
1779       return;
1780     }
1781   }
1782   layer->vtable->LayerEnablePaging(layer, value);
1783 }
1784 
LayerDefaultGetExtent(layerObj * layer,rectObj * extent)1785 int LayerDefaultGetExtent(layerObj *layer, rectObj *extent)
1786 {
1787   return MS_FAILURE;
1788 }
1789 
LayerDefaultGetAutoStyle(mapObj * map,layerObj * layer,classObj * c,shapeObj * shape)1790 int LayerDefaultGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, shapeObj *shape)
1791 {
1792   msSetError(MS_MISCERR, "'STYLEITEM AUTO' not supported for this data source.", "msLayerGetAutoStyle()");
1793   return MS_FAILURE;
1794 }
1795 
LayerDefaultCloseConnection(layerObj * layer)1796 int LayerDefaultCloseConnection(layerObj *layer)
1797 {
1798   return MS_SUCCESS;
1799 }
1800 
LayerDefaultCreateItems(layerObj * layer,const int nt)1801 int LayerDefaultCreateItems(layerObj *layer, const int nt)
1802 {
1803   if (nt > 0) {
1804     layer->items = (char **)calloc(nt, sizeof(char *)); /* should be more than enough space */
1805     MS_CHECK_ALLOC(layer->items, sizeof(char *), MS_FAILURE);
1806 
1807     layer->numitems = 0;
1808   }
1809   return MS_SUCCESS;
1810 }
1811 
LayerDefaultGetNumFeatures(layerObj * layer)1812 int LayerDefaultGetNumFeatures(layerObj *layer)
1813 {
1814     rectObj extent;
1815     int status;
1816     int result;
1817     shapeObj shape;
1818 
1819     /* calculate layer extent */
1820     if (!MS_VALID_EXTENT(layer->extent)) {
1821         if (msLayerGetExtent(layer, &extent) != MS_SUCCESS) {
1822             msSetError(MS_MISCERR, "Unable to get layer extent", "LayerDefaultGetNumFeatures()");
1823             return -1;
1824         }
1825     }
1826     else
1827         extent = layer->extent;
1828 
1829     /* Cleanup any previous item selection */
1830     msLayerFreeItemInfo(layer);
1831     if (layer->items) {
1832         msFreeCharArray(layer->items, layer->numitems);
1833         layer->items = NULL;
1834         layer->numitems = 0;
1835     }
1836 
1837     status = msLayerWhichShapes(layer, extent, MS_FALSE);
1838     if (status == MS_DONE) { /* no overlap */
1839         return 0;
1840     }
1841     else if (status != MS_SUCCESS) {
1842         return -1;
1843     }
1844 
1845     result = 0;
1846     while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) {
1847         ++result;
1848     }
1849 
1850     return result;
1851 }
1852 
LayerDefaultAutoProjection(layerObj * layer,projectionObj * projection)1853 int LayerDefaultAutoProjection(layerObj *layer, projectionObj* projection)
1854 {
1855   msSetError(MS_MISCERR, "This data driver does not implement AUTO projection support", "LayerDefaultAutoProjection()");
1856   return MS_FAILURE;
1857 }
1858 
LayerDefaultSupportsCommonFilters(layerObj * layer)1859 int LayerDefaultSupportsCommonFilters(layerObj *layer)
1860 {
1861   return MS_FALSE;
1862 }
1863 
LayerDefaultTranslateFilter(layerObj * layer,expressionObj * filter,char * filteritem)1864 int LayerDefaultTranslateFilter(layerObj *layer, expressionObj *filter, char *filteritem)
1865 {
1866   if(!filter->string) return MS_SUCCESS; /* nothing to do, not an error */
1867 
1868   msSetError(MS_MISCERR, "This data driver does not implement filter translation support", "LayerDefaultTranslateFilter()");
1869   return MS_FAILURE;
1870 }
1871 
msLayerDefaultGetPaging(layerObj * layer)1872 int msLayerDefaultGetPaging(layerObj *layer)
1873 {
1874   return MS_FALSE;
1875 }
1876 
msLayerDefaultEnablePaging(layerObj * layer,int value)1877 void msLayerDefaultEnablePaging(layerObj *layer, int value)
1878 {
1879   return;
1880 }
1881 
1882 /************************************************************************/
1883 /*                          LayerDefaultEscapeSQLParam                  */
1884 /*                                                                      */
1885 /*      Default function used to escape strings and avoid sql           */
1886 /*      injection. Specific drivers should redefine if an escaping      */
1887 /*      function is available in the driver.                            */
1888 /************************************************************************/
LayerDefaultEscapeSQLParam(layerObj * layer,const char * pszString)1889 char *LayerDefaultEscapeSQLParam(layerObj *layer, const char* pszString)
1890 {
1891   char *pszEscapedStr=NULL;
1892   if (pszString) {
1893     int nSrcLen;
1894     char c;
1895     int i=0, j=0;
1896     nSrcLen = (int)strlen(pszString);
1897     pszEscapedStr = (char*) msSmallMalloc( 2 * nSrcLen + 1);
1898     for(i = 0, j = 0; i < nSrcLen; i++) {
1899       c = pszString[i];
1900       if (c == '\'') {
1901         pszEscapedStr[j++] = '\'';
1902         pszEscapedStr[j++] = '\'';
1903       } else if (c == '\\') {
1904         pszEscapedStr[j++] = '\\';
1905         pszEscapedStr[j++] = '\\';
1906       } else
1907         pszEscapedStr[j++] = c;
1908     }
1909     pszEscapedStr[j] = 0;
1910   }
1911   return pszEscapedStr;
1912 }
1913 
1914 /************************************************************************/
1915 /*                          LayerDefaultEscapePropertyName              */
1916 /*                                                                      */
1917 /*      Return the property name in a properly escaped and quoted form. */
1918 /************************************************************************/
LayerDefaultEscapePropertyName(layerObj * layer,const char * pszString)1919 char *LayerDefaultEscapePropertyName(layerObj *layer, const char* pszString)
1920 {
1921   char* pszEscapedStr=NULL;
1922   int i, j = 0;
1923 
1924   if (layer && pszString && strlen(pszString) > 0) {
1925     int nLength = strlen(pszString);
1926 
1927     pszEscapedStr = (char*) msSmallMalloc( 1 + 2 * nLength + 1 + 1);
1928     pszEscapedStr[j++] = '"';
1929 
1930     for (i=0; i<nLength; i++) {
1931       char c = pszString[i];
1932       if (c == '"') {
1933         pszEscapedStr[j++] = '"';
1934         pszEscapedStr[j++] ='"';
1935       } else if (c == '\\') {
1936         pszEscapedStr[j++] = '\\';
1937         pszEscapedStr[j++] = '\\';
1938       } else
1939         pszEscapedStr[j++] = c;
1940     }
1941     pszEscapedStr[j++] = '"';
1942     pszEscapedStr[j++] = 0;
1943 
1944   }
1945   return pszEscapedStr;
1946 }
1947 
1948 
1949 /*
1950  * msConnectLayer
1951  *
1952  * This will connect layer object to the new layer type.
1953  * Caller is responsible to close previous layer correctly.
1954  * For Internal types the library_str is ignored, for PLUGIN it's
1955  * define what plugin to use. Returns MS_FAILURE or MS_SUCCESS.
1956  */
msConnectLayer(layerObj * layer,const int connectiontype,const char * library_str)1957 int msConnectLayer(layerObj *layer,
1958                    const int connectiontype,
1959                    const char *library_str)
1960 {
1961   layer->connectiontype = connectiontype;
1962   /* For internal types, library_str is ignored */
1963   if (connectiontype == MS_PLUGIN) {
1964     int rv;
1965     msFree(layer->plugin_library);
1966     msFree(layer->plugin_library_original);
1967 
1968     layer->plugin_library_original = msStrdup(library_str);
1969     rv = msBuildPluginLibraryPath(&layer->plugin_library,
1970                                   layer->plugin_library_original,
1971                                   layer->map);
1972     if (rv != MS_SUCCESS) {
1973       return rv;
1974     }
1975   }
1976   return msInitializeVirtualTable(layer) ;
1977 }
1978 
populateVirtualTable(layerVTableObj * vtable)1979 static int populateVirtualTable(layerVTableObj *vtable)
1980 {
1981   assert(vtable != NULL);
1982 
1983   vtable->LayerSupportsCommonFilters = LayerDefaultSupportsCommonFilters;
1984   vtable->LayerTranslateFilter = LayerDefaultTranslateFilter;
1985 
1986   vtable->LayerInitItemInfo = LayerDefaultInitItemInfo;
1987   vtable->LayerFreeItemInfo = LayerDefaultFreeItemInfo;
1988   vtable->LayerOpen = LayerDefaultOpen;
1989   vtable->LayerIsOpen = LayerDefaultIsOpen;
1990   vtable->LayerWhichShapes = LayerDefaultWhichShapes;
1991 
1992   vtable->LayerNextShape = LayerDefaultNextShape;
1993   /* vtable->LayerResultsGetShape = LayerDefaultResultsGetShape; */
1994   vtable->LayerGetShape = LayerDefaultGetShape;
1995   vtable->LayerGetShapeCount = LayerDefaultGetShapeCount;
1996   vtable->LayerClose = LayerDefaultClose;
1997   vtable->LayerGetItems = LayerDefaultGetItems;
1998   vtable->LayerGetExtent = LayerDefaultGetExtent;
1999 
2000   vtable->LayerGetAutoStyle = LayerDefaultGetAutoStyle;
2001   vtable->LayerCloseConnection = LayerDefaultCloseConnection;
2002   vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter;
2003 
2004   vtable->LayerApplyFilterToLayer = msLayerApplyPlainFilterToLayer;
2005 
2006   vtable->LayerCreateItems = LayerDefaultCreateItems;
2007 
2008   vtable->LayerGetNumFeatures = LayerDefaultGetNumFeatures;
2009 
2010   vtable->LayerGetAutoProjection = LayerDefaultAutoProjection;
2011 
2012   vtable->LayerEscapeSQLParam = LayerDefaultEscapeSQLParam;
2013 
2014   vtable->LayerEscapePropertyName = LayerDefaultEscapePropertyName;
2015 
2016   vtable->LayerEnablePaging = msLayerDefaultEnablePaging;
2017   vtable->LayerGetPaging = msLayerDefaultGetPaging;
2018 
2019   return MS_SUCCESS;
2020 }
2021 
createVirtualTable(layerVTableObj ** vtable)2022 static int createVirtualTable(layerVTableObj **vtable)
2023 {
2024   *vtable = malloc(sizeof(**vtable));
2025   MS_CHECK_ALLOC(*vtable, sizeof(**vtable), MS_FAILURE);
2026 
2027   return populateVirtualTable(*vtable);
2028 }
2029 
destroyVirtualTable(layerVTableObj ** vtable)2030 static int destroyVirtualTable(layerVTableObj **vtable)
2031 {
2032   memset(*vtable, 0, sizeof(**vtable));
2033   msFree(*vtable);
2034   *vtable = NULL;
2035   return MS_SUCCESS;
2036 }
2037 
msInitializeVirtualTable(layerObj * layer)2038 int msInitializeVirtualTable(layerObj *layer)
2039 {
2040   if (layer->vtable) {
2041     destroyVirtualTable(&layer->vtable);
2042   }
2043   createVirtualTable(&layer->vtable);
2044 
2045   if(layer->features && layer->connectiontype != MS_GRATICULE )
2046     layer->connectiontype = MS_INLINE;
2047 
2048   if(layer->tileindex && layer->connectiontype == MS_SHAPEFILE)
2049     layer->connectiontype = MS_TILED_SHAPEFILE;
2050 
2051   if(layer->type == MS_LAYER_RASTER && layer->connectiontype != MS_WMS
2052       && layer->connectiontype != MS_KERNELDENSITY)
2053     layer->connectiontype = MS_RASTER;
2054 
2055   switch(layer->connectiontype) {
2056     case(MS_INLINE):
2057       return(msINLINELayerInitializeVirtualTable(layer));
2058       break;
2059     case(MS_SHAPEFILE):
2060       return(msSHPLayerInitializeVirtualTable(layer));
2061       break;
2062     case(MS_TILED_SHAPEFILE):
2063       return(msTiledSHPLayerInitializeVirtualTable(layer));
2064       break;
2065     case(MS_OGR):
2066       return(msOGRLayerInitializeVirtualTable(layer));
2067       break;
2068     case(MS_POSTGIS):
2069       return(msPostGISLayerInitializeVirtualTable(layer));
2070       break;
2071     case(MS_WMS):
2072       /* WMS should be treated as a raster layer */
2073       return(msRASTERLayerInitializeVirtualTable(layer));
2074       break;
2075     case(MS_KERNELDENSITY):
2076       /* KERNELDENSITY should be treated as a raster layer */
2077       return(msRASTERLayerInitializeVirtualTable(layer));
2078       break;
2079     case(MS_ORACLESPATIAL):
2080       return(msOracleSpatialLayerInitializeVirtualTable(layer));
2081       break;
2082     case(MS_WFS):
2083       return(msWFSLayerInitializeVirtualTable(layer));
2084       break;
2085     case(MS_GRATICULE):
2086       return(msGraticuleLayerInitializeVirtualTable(layer));
2087       break;
2088     case(MS_RASTER):
2089       return(msRASTERLayerInitializeVirtualTable(layer));
2090       break;
2091     case(MS_PLUGIN):
2092       return(msPluginLayerInitializeVirtualTable(layer));
2093       break;
2094     case(MS_UNION):
2095       return(msUnionLayerInitializeVirtualTable(layer));
2096       break;
2097     case(MS_UVRASTER):
2098       return(msUVRASTERLayerInitializeVirtualTable(layer));
2099       break;
2100     case(MS_CONTOUR):
2101       return(msContourLayerInitializeVirtualTable(layer));
2102       break;
2103     default:
2104       msSetError(MS_MISCERR, "Unknown connectiontype, it was %d", "msInitializeVirtualTable()", layer->connectiontype);
2105       return MS_FAILURE;
2106       break;
2107   }
2108 
2109   /* not reached */
2110   return MS_FAILURE;
2111 }
2112 
2113 /*
2114  * INLINE: Virtual table functions
2115  */
2116 
2117 typedef struct {
2118   rectObj searchrect;
2119   int is_relative; /* relative coordinates? */
2120 }
2121 msINLINELayerInfo;
2122 
msINLINELayerIsOpen(layerObj * layer)2123 int msINLINELayerIsOpen(layerObj *layer)
2124 {
2125   if (layer->layerinfo)
2126     return(MS_TRUE);
2127   else
2128     return(MS_FALSE);
2129 }
2130 
msINLINECreateLayerInfo(void)2131 msINLINELayerInfo *msINLINECreateLayerInfo(void)
2132 {
2133   msINLINELayerInfo *layerinfo = msSmallMalloc(sizeof(msINLINELayerInfo));
2134   layerinfo->searchrect.minx = -1.0;
2135   layerinfo->searchrect.miny = -1.0;
2136   layerinfo->searchrect.maxx = -1.0;
2137   layerinfo->searchrect.maxy = -1.0;
2138   layerinfo->is_relative = MS_FALSE;
2139   return layerinfo;
2140 }
2141 
msINLINELayerOpen(layerObj * layer)2142 int msINLINELayerOpen(layerObj *layer)
2143 {
2144   msINLINELayerInfo  *layerinfo;
2145 
2146   if (layer->layerinfo) {
2147     if (layer->debug) {
2148       msDebug("msINLINELayerOpen: Layer is already open!\n");
2149     }
2150     return MS_SUCCESS;  /* already open */
2151   }
2152 
2153   /*
2154   ** Initialize the layerinfo
2155   **/
2156   layerinfo = msINLINECreateLayerInfo();
2157 
2158   layer->currentfeature = layer->features; /* point to the begining of the feature list */
2159 
2160   layer->layerinfo = (void*)layerinfo;
2161 
2162   return(MS_SUCCESS);
2163 }
2164 
msINLINELayerClose(layerObj * layer)2165 int msINLINELayerClose(layerObj *layer)
2166 {
2167   if (layer->layerinfo) {
2168     free(layer->layerinfo);
2169     layer->layerinfo = NULL;
2170   }
2171 
2172   return MS_SUCCESS;
2173 }
2174 
msINLINELayerWhichShapes(layerObj * layer,rectObj rect,int isQuery)2175 int msINLINELayerWhichShapes(layerObj *layer, rectObj rect, int isQuery)
2176 {
2177   msINLINELayerInfo *layerinfo = NULL;
2178   layerinfo = (msINLINELayerInfo*) layer->layerinfo;
2179 
2180   layerinfo->searchrect = rect;
2181   layerinfo->is_relative = (layer->transform != MS_FALSE && layer->transform != MS_TRUE);
2182 
2183   return MS_SUCCESS;
2184 }
2185 
2186 /* Author: Cristoph Spoerri and Sean Gillies */
msINLINELayerGetShape(layerObj * layer,shapeObj * shape,resultObj * record)2187 int msINLINELayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record)
2188 {
2189   int i=0;
2190   featureListNodeObjPtr current;
2191 
2192   int shapeindex = record->shapeindex; /* only index necessary */
2193 
2194   current = layer->features;
2195   while (current!=NULL && i!=shapeindex) {
2196     i++;
2197     current = current->next;
2198   }
2199   if (current == NULL) {
2200     msSetError(MS_SHPERR, "No inline feature with this index.", "msINLINELayerGetShape()");
2201     return MS_FAILURE;
2202   }
2203 
2204   if (msCopyShape(&(current->shape), shape) != MS_SUCCESS) {
2205     msSetError(MS_SHPERR, "Cannot retrieve inline shape. There some problem with the shape", "msINLINELayerGetShape()");
2206     return MS_FAILURE;
2207   }
2208   /* check for the expected size of the values array */
2209   if (layer->numitems > shape->numvalues) {
2210     shape->values = (char **)msSmallRealloc(shape->values, sizeof(char *)*(layer->numitems));
2211     for (i = shape->numvalues; i < layer->numitems; i++)
2212       shape->values[i] = msStrdup("");
2213   }
2214   msComputeBounds(shape);
2215   return MS_SUCCESS;
2216 }
2217 
msINLINELayerNextShape(layerObj * layer,shapeObj * shape)2218 int msINLINELayerNextShape(layerObj *layer, shapeObj *shape)
2219 {
2220   msINLINELayerInfo *layerinfo = NULL;
2221   shapeObj * s;
2222 
2223   layerinfo = (msINLINELayerInfo*) layer->layerinfo;
2224 
2225   while (1) {
2226 
2227     if( ! (layer->currentfeature)) {
2228       /* out of features */
2229       return(MS_DONE);
2230     }
2231 
2232     s = &(layer->currentfeature->shape);
2233     layer->currentfeature = layer->currentfeature->next;
2234     msComputeBounds(s);
2235 
2236     if (layerinfo->is_relative || msRectOverlap(&s->bounds, &layerinfo->searchrect)) {
2237 
2238       msCopyShape(s, shape);
2239 
2240       /* check for the expected size of the values array */
2241       if (layer->numitems > shape->numvalues) {
2242         int i;
2243         shape->values = (char **)msSmallRealloc(shape->values, sizeof(char *)*(layer->numitems));
2244         for (i = shape->numvalues; i < layer->numitems; i++)
2245           shape->values[i] = msStrdup("");
2246         shape->numvalues = layer->numitems;
2247       }
2248 
2249       break;
2250     }
2251 
2252   }
2253 
2254   return(MS_SUCCESS);
2255 }
2256 
msINLINELayerGetNumFeatures(layerObj * layer)2257 int msINLINELayerGetNumFeatures(layerObj *layer)
2258 {
2259   int i = 0;
2260   featureListNodeObjPtr current;
2261 
2262   current = layer->features;
2263   while (current != NULL) {
2264     i++;
2265     current = current->next;
2266   }
2267   return i;
2268 }
2269 
2270 
2271 
2272 /*
2273 Returns an escaped string
2274 */
msLayerEscapeSQLParam(layerObj * layer,const char * pszString)2275 char  *msLayerEscapeSQLParam(layerObj *layer, const char*pszString)
2276 {
2277   if ( ! layer->vtable) {
2278     int rv =  msInitializeVirtualTable(layer);
2279     if (rv != MS_SUCCESS)
2280       return "";
2281   }
2282   return layer->vtable->LayerEscapeSQLParam(layer, pszString);
2283 }
2284 
msLayerEscapePropertyName(layerObj * layer,const char * pszString)2285 char  *msLayerEscapePropertyName(layerObj *layer, const char*pszString)
2286 {
2287   if ( ! layer->vtable) {
2288     int rv =  msInitializeVirtualTable(layer);
2289     if (rv != MS_SUCCESS)
2290       return "";
2291   }
2292   return layer->vtable->LayerEscapePropertyName(layer, pszString);
2293 }
2294 
2295 
2296 int
msINLINELayerInitializeVirtualTable(layerObj * layer)2297 msINLINELayerInitializeVirtualTable(layerObj *layer)
2298 {
2299   assert(layer != NULL);
2300   assert(layer->vtable != NULL);
2301 
2302   /* layer->vtable->LayerInitItemInfo, use default */
2303   /* layer->vtable->LayerFreeItemInfo, use default */
2304   layer->vtable->LayerOpen = msINLINELayerOpen;
2305   layer->vtable->LayerIsOpen = msINLINELayerIsOpen;
2306   layer->vtable->LayerWhichShapes = msINLINELayerWhichShapes;
2307   layer->vtable->LayerNextShape = msINLINELayerNextShape;
2308   /* layer->vtable->LayerGetShapeCount, use default */
2309   layer->vtable->LayerGetShape = msINLINELayerGetShape;
2310   layer->vtable->LayerClose = msINLINELayerClose;
2311   /* layer->vtable->LayerGetItems, use default */
2312 
2313   /*
2314    * Original code contained following
2315    * TODO: need to compute extents
2316    */
2317   /* layer->vtable->LayerGetExtent, use default */
2318 
2319   /* layer->vtable->LayerGetAutoStyle, use default */
2320   /* layer->vtable->LayerCloseConnection, use default */
2321   layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter;
2322 
2323   /* layer->vtable->LayerApplyFilterToLayer, use default */
2324 
2325   /* layer->vtable->LayerCreateItems, use default */
2326   layer->vtable->LayerGetNumFeatures = msINLINELayerGetNumFeatures;
2327 
2328   /*layer->vtable->LayerEscapeSQLParam, use default*/
2329   /*layer->vtable->LayerEscapePropertyName, use default*/
2330 
2331   /* layer->vtable->LayerEnablePaging, use default */
2332   /* layer->vtable->LayerGetPaging, use default */
2333 
2334   return MS_SUCCESS;
2335 }
2336 
2337 
2338