Index: Makefile.vc
===================================================================
--- Makefile.vc	(revision 6223)
+++ Makefile.vc	(working copy)
@@ -41,7 +41,8 @@
         mapogcfilter.obj mapogcsld.obj mapthread.obj mapobject.obj \
 		classobject.obj layerobject.obj mapwcs.obj mapgeos.obj strptime.obj \
 		mapcpl.obj mapio.obj mappool.obj mapsvg.obj mapregex.obj mappluginlayer.obj \
-                mapogcsos.obj mappostgresql.obj mapcrypto.obj mapowscommon.obj \
+        mapogcsos.obj mappostgresql.obj mapcrypto.obj mapowscommon.obj \
+        mapcache.obj mapgeomtrans.obj mapfilter.obj \
 		$(EPPL_OBJ) $(REGEX_OBJ)
 
 MS_HDRS = 	map.h mapfile.h
@@ -90,9 +91,9 @@
 .c.exe:
 	$(CC) $(CFLAGS) /c $*.c /Fo$*.obj
 !IFDEF DLLBUILD
-	$(LINK) $(LDFLAGS) $*.obj $(LIBS_DLL)
+	$(LINK) $(LDFLAGS) $(LDEBUG)  $*.obj $(LIBS_DLL)
 !ELSE
-        $(LINK) $(LDFLAGS) $*.obj $(LIBS)
+        $(LINK) $(LDFLAGS) $(LDEBUG)  $*.obj $(LIBS)
 !ENDIF
 	if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1
 
@@ -100,7 +101,7 @@
 	del *.obj
 	del $(REGEX_OBJ)
 	del *.lib
-	del *.dll
+#	del *.dll
 	del $(MS_EXE)
 	del *.pdb
 	del *.exp
Index: map.h
===================================================================
--- map.h	(revision 6223)
+++ map.h	(working copy)
@@ -328,7 +328,7 @@
 
 enum MS_BITMAP_FONT_SIZES {MS_TINY , MS_SMALL, MS_MEDIUM, MS_LARGE, MS_GIANT};
 enum MS_QUERYMAP_STYLES {MS_NORMAL, MS_HILITE, MS_SELECTED};
-enum MS_CONNECTION_TYPE {MS_INLINE, MS_SHAPEFILE, MS_TILED_SHAPEFILE, MS_SDE, MS_OGR, MS_UNUSED_1, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_MYGIS, MS_RASTER, MS_PLUGIN };
+enum MS_CONNECTION_TYPE {MS_INLINE, MS_SHAPEFILE, MS_TILED_SHAPEFILE, MS_SDE, MS_OGR, MS_UNUSED_1, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_MYGIS, MS_RASTER, MS_PLUGIN, MS_GEOMTRANS, MS_LAYERFILTER, MS_CACHE };
 enum MS_JOIN_CONNECTION_TYPE {MS_DB_XBASE, MS_DB_CSV, MS_DB_MYSQL, MS_DB_ORACLE, MS_DB_POSTGRES};
 enum MS_JOIN_TYPE {MS_JOIN_ONE_TO_ONE, MS_JOIN_ONE_TO_MANY};
 
@@ -1051,6 +1051,11 @@
 #ifdef SWIG
 %mutable;
 #endif /* SWIG */
+
+#ifndef SWIG
+  struct layer_obj **layers;
+  int numlayers; /* number of sublayers in layer */
+#endif /* SWIG */
 } layerObj;
 
 
@@ -1249,6 +1254,7 @@
 
     int (*LayerCreateItems)(layerObj *layer, int nt);
     int (*LayerGetNumFeatures)(layerObj *layer);
+    void (*LayerDestroy)(layerObj *layer);
 };
 #endif /*SWIG*/
 
@@ -1600,7 +1606,7 @@
 MS_DLL_EXPORT int msInitializeVirtualTable(layerObj *layer);
 MS_DLL_EXPORT int msConnectLayer(layerObj *layer, const int connectiontype, 
                                  const char *library_str);
-
+MS_DLL_EXPORT layerObj *msGetSubLayer(layerObj *layer, char* path);
 MS_DLL_EXPORT int msINLINELayerInitializeVirtualTable(layerObj *layer);
 MS_DLL_EXPORT int msShapeFileLayerInitializeVirtualTable(layerObj *layer);
 MS_DLL_EXPORT int msTiledSHPLayerInitializeVirtualTable(layerObj *layer);
Index: mapfile.c
===================================================================
--- mapfile.c	(revision 6223)
+++ mapfile.c	(working copy)
@@ -2380,6 +2380,9 @@
   for (i=0;i<MS_MAXCLASSES;i++) {
   	layer->class[i]=NULL;
   }
+
+  layer->layers = NULL;
+  layer->numlayers = 0;
   
   layer->name = NULL;
   layer->group = NULL;
@@ -2490,6 +2493,9 @@
 //  if (layer->debug)
 //     msDebug("freeLayer(): freeing layer at %p.\n",layer);
 
+  if (layer->vtable)
+      layer->vtable->LayerDestroy(layer);
+
   msFree(layer->name);
   msFree(layer->group);
   msFree(layer->data);
@@ -2543,6 +2549,16 @@
   msFree(layer->joins);
   layer->numjoins = 0;
 
+  for (i=0;i<layer->numlayers;i++) {
+      if ( freeLayer(layer->layers[i]) == MS_SUCCESS)
+	    	free(layer->layers[i]);
+  }
+  if (layer->layers) {
+      free(layer->layers);
+      layer->layers = NULL;
+  }
+  layer->numlayers = 0;
+
   return MS_SUCCESS;
 }
 
@@ -2580,7 +2596,7 @@
       if(getString(&layer->connection) == MS_FAILURE) return(-1);
       break;
     case(CONNECTIONTYPE):
-      if((layer->connectiontype = getSymbol(9, MS_SDE, MS_OGR, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_MYGIS, MS_PLUGIN)) == -1) return(-1);
+      if((layer->connectiontype = getSymbol(12, MS_SDE, MS_OGR, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_MYGIS, MS_PLUGIN, MS_GEOMTRANS, MS_LAYERFILTER, MS_CACHE)) == -1) return(-1);
       break;
     case(DATA):
       if(getString(&layer->data) == MS_FAILURE) return(-1);
@@ -2783,6 +2799,20 @@
     case(UNITS):
       if((layer->units = getSymbol(8, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_DD,MS_PIXELS,MS_PERCENTAGES)) == -1) return(-1);
       break;
+    case (LAYER):
+      if(layer->numlayers == 0)
+          layer->layers = (layerObj**) malloc(sizeof(layerObj*));
+      else
+          layer->layers = (layerObj**) realloc(layer->layers, sizeof(layerObj*) * (layer->numlayers));
+      layer->layers[layer->numlayers]=(layerObj*)malloc(sizeof(layerObj));
+      if (layer->layers[layer->numlayers] == NULL) {
+           msSetError(MS_MEMERR, "Malloc of a new layer failed.", "loadLayer()");
+	       return MS_FAILURE;
+      }
+      if(loadLayer(layer->layers[layer->numlayers], map) == -1) return MS_FAILURE;
+      layer->layers[layer->numlayers]->index = layer->numlayers; /* save the index */
+      ++layer->numlayers;
+      break;
     default:
       msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadLayer()",
                  msyytext, msyylineno);      
Index: maphash.c
===================================================================
--- maphash.c	(revision 6223)
+++ maphash.c	(working copy)
@@ -32,14 +32,14 @@
 
 MS_CVSID("$Id$")
 
-static unsigned hash(const char *key)
+static unsigned hash(const char *key, int hashSize)
 {
   unsigned hashval;
   
   for(hashval=0; *key!='\0'; key++)
     hashval = tolower(*key) + 31 * hashval;
 
-  return(hashval % MS_HASHSIZE);
+  return(hashval % hashSize);
 }
 
 hashTableObj *msCreateHashTable() 
@@ -49,6 +49,7 @@
     
     table = (hashTableObj *) malloc(sizeof(hashTableObj));
     table->items = (struct hashObj **) malloc(sizeof(struct hashObj *)*MS_HASHSIZE);
+    table->hashSize = MS_HASHSIZE;
     
     for (i=0; i<MS_HASHSIZE; i++)
         table->items[i] = NULL;
@@ -57,21 +58,28 @@
     return table;
 }
 
-int initHashTable( hashTableObj *table ) 
+int initHashTableEx( hashTableObj *table, int hashSize )
 {
     int i;
 
-    table->items = (struct hashObj **) malloc(sizeof(struct hashObj *)*MS_HASHSIZE);
+    table->items = (struct hashObj **) malloc(sizeof(struct hashObj *)*hashSize);
     if (!table->items) {
         msSetError(MS_MEMERR, "Failed to allocate memory for items", "initHashTable");
         return MS_FAILURE;
     }
-    for (i=0; i<MS_HASHSIZE; i++)
+    for (i=0; i<hashSize; i++)
         table->items[i] = NULL;
     table->numitems = 0;
+    table->DestroyData = free;
+    table->hashSize = hashSize;
     return MS_SUCCESS;
 }
 
+int initHashTable( hashTableObj *table ) 
+{
+    return initHashTableEx(table, MS_HASHSIZE);
+}
+
 void msFreeHashTable( hashTableObj *table )
 {
     if( table != NULL )
@@ -92,7 +100,7 @@
     {
         if (table->items)
         {
-            for (i=0; i<MS_HASHSIZE; i++) 
+            for (i=0; i<table->hashSize; i++) 
             {
                 if (table->items[i] != NULL) 
                 {
@@ -101,7 +109,7 @@
                          prev_tp=tp,tp=tp->next,free(prev_tp)) 
                     {
 	                    free(tp->key);
-	                    free(tp->data);
+                        table->DestroyData(tp->data);
                     }
                 }
                 if (tp) free(tp);
@@ -120,7 +128,36 @@
     }
 }
 
-struct hashObj *msInsertHashTable(hashTableObj *table, 
+void msClearHashItems( hashTableObj *table )
+{
+    int i;
+    struct hashObj *tp=NULL;
+    struct hashObj *prev_tp=NULL;
+
+    if (table)
+    {
+        if (table->items)
+        {
+            for (i=0; i<table->hashSize; i++) 
+            {
+                if (table->items[i] != NULL) 
+                {
+                    for (tp=table->items[i];
+                         tp!=NULL; 
+                         prev_tp=tp,tp=tp->next,free(prev_tp)) 
+                    {
+	                    free(tp->key);
+                        table->DestroyData(tp->data);
+                    }
+                }
+                if (tp) free(tp);
+                table->items[i] = NULL;
+            }
+        }
+    }
+}
+
+struct hashObj *msInsertHashTablePtr(hashTableObj *table, 
                                   const char *key, const char *value)
 {
     struct hashObj *tp;
@@ -132,7 +169,7 @@
         return NULL;
     }
 
-    for (tp=table->items[hash(key)]; tp!=NULL; tp=tp->next)
+    for (tp=table->items[hash(key, table->hashSize)]; tp!=NULL; tp=tp->next)
         if(strcasecmp(key, tp->key) == 0)
             break;
 
@@ -142,20 +179,26 @@
             msSetError(MS_HASHERR, "No such hash entry", "msInsertHashTable");
             return NULL;
         }
-        hashval = hash(key);
+        hashval = hash(key, table->hashSize);
         tp->next = table->items[hashval];
         table->items[hashval] = tp;
         table->numitems++;
     } else {
-        free(tp->data);
+        table->DestroyData(tp->data);
     }
 
-    if ((tp->data = strdup(value)) == NULL)
+    if ((tp->data = (char*)value) == NULL)
         return NULL;
 
     return tp;
 }
 
+struct hashObj *msInsertHashTable(hashTableObj *table, 
+                                  const char *key, const char *value)
+{
+    return msInsertHashTablePtr(table, key, strdup(value));
+}
+
 char *msLookupHashTable(hashTableObj *table, const char *key)
 {
     struct hashObj *tp;
@@ -164,7 +207,7 @@
         return(NULL);
     }
 
-    for (tp=table->items[hash(key)]; tp!=NULL; tp=tp->next)
+    for (tp=table->items[hash(key, table->hashSize)]; tp!=NULL; tp=tp->next)
         if (strcasecmp(key, tp->key) == 0)
             return(tp->data);
 
@@ -182,7 +225,7 @@
         return MS_FAILURE;
     }
   
-    tp=table->items[hash(key)];
+    tp=table->items[hash(key, table->hashSize)];
     if (!tp) {
         msSetError(MS_HASHERR, "No such hash entry", "msRemoveHashTable");
         return MS_FAILURE;
@@ -193,11 +236,15 @@
         if (strcasecmp(key, tp->key) == 0) {
             if (prev_tp) {     
                 prev_tp->next = tp->next;
+                if (tp->key) free(tp->key);
+                if (tp->data) table->DestroyData(tp->data);
                 free(tp);
                 break;
             }
             else {
-                table->items[hash(key)] = NULL;
+                table->items[hash(key, table->hashSize)] = NULL;
+                if (tp->key) free(tp->key);
+                if (tp->data) table->DestroyData(tp->data);
                 free(tp);
                 break;
             }
@@ -224,7 +271,7 @@
         return NULL;
     }
     
-    for (hash_index = 0; hash_index < MS_HASHSIZE; hash_index++ ) {
+    for (hash_index = 0; hash_index < table->hashSize; hash_index++ ) {
         if (table->items[hash_index] != NULL )
             return table->items[hash_index]->key;
     }
@@ -245,7 +292,7 @@
     if ( lastKey == NULL )
         return msFirstKeyFromHashTable( table );
 
-    hash_index = hash(lastKey);
+    hash_index = hash(lastKey, table->hashSize);
     for ( link = table->items[hash_index]; 
          link != NULL && strcasecmp(lastKey,link->key) != 0;
          link = link->next ) {}
@@ -253,7 +300,7 @@
     if ( link != NULL && link->next != NULL )
         return link->next->key;
 
-    while ( ++hash_index < MS_HASHSIZE ) {
+    while ( ++hash_index < table->hashSize ) {
         if ( table->items[hash_index] != NULL )
             return table->items[hash_index]->key;
     }
@@ -261,3 +308,64 @@
     return NULL;
 }
 
+struct hashObj *msFirstItemFromHashTable( hashTableObj *table)
+{
+    int i;
+
+    if (!table) {
+        msSetError(MS_HASHERR, "No hash table", "msFirstItemFromHashTable");
+        return NULL;
+    }
+
+    for (i=0; i<table->hashSize; i++) {
+        if (table->items[i])
+            return table->items[i];
+    }
+
+    return NULL;
+}
+
+struct hashObj *msNextItemFromHashTable( hashTableObj *table, struct hashObj *lastItem )
+{
+    int i;
+
+    if (!table) {
+        msSetError(MS_HASHERR, "No hash table", "msNextItemFromHashTable");
+        return NULL;
+    }
+
+    if ( !lastItem )
+        return msFirstItemFromHashTable( table );
+
+    if (lastItem->next)
+        return lastItem->next;
+    
+    for (i=hash(lastItem->key, table->hashSize)+1; i<table->hashSize; i++) {
+        if (table->items[i])
+            return table->items[i];
+    }
+
+    return NULL;
+}
+
+int msGetHashTableItemCount(hashTableObj *table)
+{
+    int i, count;
+    struct hashObj *current;
+
+    if (!table) {
+        msSetError(MS_HASHERR, "No hash table", "msHashTableItemCount");
+        return 0;
+    }
+
+    count = 0;
+    for (i=0; i<table->hashSize; i++) {
+        current = table->items[i];
+        while(current) {
+            ++count;
+            current = current->next;
+        }
+    }
+
+    return count;
+}
Index: maphash.h
===================================================================
--- maphash.h	(revision 6223)
+++ maphash.h	(working copy)
@@ -56,6 +56,8 @@
 typedef struct {
 #ifndef SWIG
     struct hashObj **items;  /* the hash table */
+    void (*DestroyData)(char *data);
+    int hashSize;
 #endif
 #ifdef SWIG
 %immutable;
@@ -142,6 +144,33 @@
  */
 MS_DLL_EXPORT const char *msNextKeyFromHashTable( hashTableObj *table,
                                                   const char *prevkey );
+
+/* msFirstItemFromHashTable - get the first item
+ * ARGS:
+ *     table - target hash table
+ * RETURNS:
+ *     first item as a hashObj
+ */
+MS_DLL_EXPORT struct hashObj *msFirstItemFromHashTable( hashTableObj *table );
+
+/* msNextItemFromHashTable - get next item
+ * ARGS:
+ *     table - target hash table
+ *     prevItem - the previous item
+ * RETURNS:
+ *     the hashObj of the item of following prevItem hashObj
+ */
+MS_DLL_EXPORT struct hashObj *msNextItemFromHashTable( hashTableObj *table,
+                                                  const struct hashObj *prevItem );
+
+/* msGetHashTableItemCount - get item count
+ * ARGS:
+ *     table - target hash table
+ * RETURNS:
+ *     the count of the items in the hashtable
+ */
+MS_DLL_EXPORT int msGetHashTableItemCount(hashTableObj *table);
+
 #endif /*SWIG*/
 
 #ifdef __cplusplus
Index: maplayer.c
===================================================================
--- maplayer.c	(revision 6223)
+++ maplayer.c	(working copy)
@@ -1078,6 +1078,11 @@
     return MS_FAILURE;
 }
 
+void
+LayerDefaultDestroy(layerObj *layer)
+{
+}
+
 /*
  * msConnectLayer
  *
@@ -1134,6 +1139,7 @@
     vtable->LayerCreateItems = LayerDefaultCreateItems;
     
     vtable->LayerGetNumFeatures = LayerDefaultGetNumFeatures;
+    vtable->LayerDestroy = LayerDefaultDestroy;
 
     return MS_SUCCESS;
 }
@@ -1217,6 +1223,15 @@
         case(MS_PLUGIN):
             return(msPluginLayerInitializeVirtualTable(layer));
             break;
+        case(MS_GEOMTRANS):
+            return(msGeomTransLayerInitializeVirtualTable(layer));
+            break;
+        case(MS_LAYERFILTER):
+            return(msFilterLayerInitializeVirtualTable(layer));
+            break;
+        case(MS_CACHE):
+            return(msCacheLayerInitializeVirtualTable(layer));
+            break;
         default:
             msSetError(MS_MISCERR, 
                        "Unknown connectiontype, it was %d", 
@@ -1332,3 +1347,41 @@
 
     return MS_SUCCESS;
 }
+
+layerObj* msGetSubLayer(layerObj *layer, char* path)
+{
+    int size, i;
+    
+    if (path == NULL || *path == 0)
+        return NULL;
+    
+    if (path[0] == '/') {
+        /* root layer */
+        size = 1;
+        while (path[size] && path[size] != '/')
+            ++size;
+        for (i=0; i<layer->map->numlayers; i++) {
+            if (layer->map->layers[i] && strncmp(&path[1], layer->map->layers[i]->name, size - 1) == 0) {
+                if (path[size] == '/')
+                    return msGetSubLayer(layer->map->layers[i], &path[size+1]);
+                else
+                    return layer->map->layers[i];
+            }
+        }
+    }
+    else
+    {
+        size = 0;
+        while (path[size] && path[size] != '/')
+            ++size;
+        for (i=0; i<layer->numlayers; i++) {
+            if (layer->layers[i] && strncmp(path, layer->layers[i]->name, size) == 0) {
+                if (path[size] == '/')
+                    return msGetSubLayer(layer->layers[i], &path[size+1]);
+                else 
+                    return layer->layers[i]; 
+            }
+        }
+    }
+    return NULL;
+}
Index: maplexer.l
===================================================================
--- maplexer.l	(revision 6223)
+++ maplexer.l	(working copy)
@@ -318,6 +318,9 @@
 <INITIAL,VALUE_STRING>normal                   { return(MS_NORMAL); }
 <INITIAL,VALUE_STRING>off                      { return(MS_OFF); }
 <INITIAL,VALUE_STRING>ogr                      { return(MS_OGR); }
+<INITIAL,VALUE_STRING>geomtrans                { return(MS_GEOMTRANS); }
+<INITIAL,VALUE_STRING>layerfilter              { return(MS_LAYERFILTER); }
+<INITIAL,VALUE_STRING>cache                    { return(MS_CACHE); }
 <INITIAL,VALUE_STRING>on                       { return(MS_ON); }
 <INITIAL,VALUE_STRING>one-to-one               { return(MS_JOIN_ONE_TO_ONE); }
 <INITIAL,VALUE_STRING>one-to-many              { return(MS_JOIN_ONE_TO_MANY); }

