Index: src/com/iver/cit/gvsig/fmap/core/ShapeZMFactory.java
===================================================================
--- src/com/iver/cit/gvsig/fmap/core/ShapeZMFactory.java	(revision 0)
+++ src/com/iver/cit/gvsig/fmap/core/ShapeZMFactory.java	(revision 0)
@@ -0,0 +1,93 @@
+package com.iver.cit.gvsig.fmap.core;
+
+
+/**
+ * This factory is used to create geoemtries with the M and Z coordinates
+ * 
+ * @author Flavio Pompermaier (flavio.pompermaier@sinergis.it)
+ */
+public class ShapeZMFactory {
+	//TODO implement
+	//		public static IGeometry createPoint3DM(double x, double y,double z, double m) {
+	//			return new FGeometryM(new FPoint3DM(x, y, z, m));
+	//		}
+	
+	public static IGeometryM createPolyline3DM(FPolyline3DM polyline) {
+		return new FGeometryM(polyline);
+	}
+	
+	//TODO implement
+	//		public static IGeometry createPolyline3DM(ByteBuffer data) {
+	//
+	//			int count = data.getInt();
+	//			GeneralPathX gp = new GeneralPathX();
+	//			//double[] ms = new double[count - 1];
+	//			//ArrayList alMs = new ArrayList();
+	//
+	//			ArrayList<Double> ms = new ArrayList<Double>();
+	//			//		        ArrayList<Double> ms_aux = null;
+	//			//		        double[] ms = null;      //Intento de evitar el tener que encapsular las m's en
+	//			//		        double[] ms_aux = null;  //objetos Double y de tener que recorrer un ArrayList
+	//			int ms_lentgh = 0;
+	//
+	//			for (int i=0; i < count; i++) {
+	//				parseTypeAndSRID(data);
+	//				FPoint2DM[] points = parsePointArray(data);
+	//				//		            ms_aux = new double[ms_lentgh + points.length];
+	//
+	//				gp.moveTo(points[0].getX(), points[0].getY());
+	//				//alMs.add(new Double(points[0].getM()));
+	//				//		            ms_aux[ms_lentgh + 0] = points[0].getM();
+	//				ms.add(points[0].getM());
+	//
+	//				for (int j = 1; j< points.length; j++) {
+	//					ms.add(points[j].getM());
+	//					//		             ms_aux[ms_lentgh + j] = points[j].getM();
+	//					gp.lineTo(points[j].getX(), points[j].getY());
+	//				} 
+	//
+	//				//ms[i] = points[i].getM();
+	//				//		            if (ms != null) {
+	//				//		             System.arraycopy(ms, 0, ms_aux, ms.length, ms.length);
+	//				//		            }
+	//				//		            ms = ms_aux;
+	//				//		            ms_lentgh = ms.length;
+	//				//		            ms_aux = null;
+	//			}//for
+	//
+	//
+	//			// OJO: Para ahorrarme esto tendría que modificar la clase FPolyline2DM para
+	//			//      que las ms se almacenaran como objetos Double en lugar de usar el tipo
+	//			//      primitivo double.
+	//			double[] aMs = new double[ms.size()];
+	//			for (int i = 0; i < ms.size(); i++) {
+	//				aMs[i] = ((Double)ms.get(i)).doubleValue();
+	//			}
+	//
+	//			return new FGeometryM(new FPolyline3DM(gp, aMs));
+	//		}
+	
+	public static IGeometry createPolygon3DM(GeneralPathX shape, double[] pZ, double[] pM) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public static IGeometry createMultipoint3DM(double[] x, double[] y, double[] z, double[] m) {
+		throw new UnsupportedOperationException();
+	}
+	
+	/**
+	 * Creates a Polyline in 3D with the Z and M coordinates.
+	 * 
+	 * @param shape
+	 *            Coordinates to create the polyline
+	 * @param pZ
+	 *            Vector de Z.
+	 * @param pM
+	 *            Vector de M.
+	 * @return Geometría.
+	 * @author Flavio Pompermaier
+	 */
+	public static IGeometry createPolyline3DM(GeneralPathX shape, double[] pZ, double[] pM) {
+		return new FGeometry(new FPolyline3DM(shape, pZ, pM));
+	}
+}
\ No newline at end of file
Index: src/com/iver/cit/gvsig/fmap/core/FPolyline3DM.java
===================================================================
--- src/com/iver/cit/gvsig/fmap/core/FPolyline3DM.java	(revision 0)
+++ src/com/iver/cit/gvsig/fmap/core/FPolyline3DM.java	(revision 0)
@@ -0,0 +1,166 @@
+package com.iver.cit.gvsig.fmap.core;
+
+import java.awt.geom.PathIterator;
+
+import com.iver.cit.gvsig.fmap.core.v02.FConverter;
+
+/**
+ * The Class FPolyline3DM that manages correctly (with Z and M) PolylineZs
+ * 
+ * @author Pompermaier Flavio
+ */
+public class FPolyline3DM extends FPolyline3D implements FShapeM {
+	
+	private static final long serialVersionUID = -4920745174292188836L;
+	private static final String NAME = "MULTILINESTRING_3DM";
+	double[] pM = null;
+	
+	/**
+	 * Crea un nuevo Polyline3DM.
+	 * 
+	 * @param gpx
+	 *            GeneralPathX
+	 * @param pZ
+	 *            Vector con la Z.
+	 * @param pM
+	 *            Vector con la M.
+	 */
+	public FPolyline3DM(GeneralPathX gpx, double[] pZ, double[] pM) {
+		super(gpx, pZ);
+		this.pM = pM;
+	}
+	
+	/**
+	 * @see com.iver.cit.gvsig.fmap.core.FShape#getShapeType()
+	 */
+	@Override
+	public int getShapeType() {
+		return FShape.LINE | FShape.Z;
+	}
+	
+	/**
+	 * Devuelve un Array con todos los valores de M.
+	 * 
+	 * @return Array de Ms.
+	 */
+	public double[] getMs() {
+		return pM;
+	}
+	
+	/*
+	 * (non-Javadoc)
+	 * @see com.iver.cit.gvsig.fmap.core.FShape#cloneFShape()
+	 */
+	@Override
+	public FShape cloneFShape() {
+		return new FPolyline3DM((GeneralPathX) gp.clone(), pZ, pM);
+	}
+	
+	
+	/*
+	 * (non-Javadoc)
+	 * @see com.iver.cit.gvsig.fmap.core.FShapeM#isDecreasing()
+	 */
+	public boolean isDecreasing() {
+		if (pM.length == 0)
+			return false;
+		return pM[0] > pM[pM.length - 1];
+	}
+	
+	
+	/*
+	 * (non-Javadoc)
+	 * @see com.iver.cit.gvsig.fmap.core.FShapeM#revertMs()
+	 */
+	public void revertMs() {
+		double totalDistance = Math.abs(pM[0] - pM[pM.length - 1]);
+		double[] percentages = new double[pM.length];
+		for (int i = 1; i < percentages.length; i++) {
+			percentages[i] = Math.abs(pM[i] - pM[i - 1]) / totalDistance;
+		}
+		//The first value
+		double pm0 = pM[0];
+		if (!isDecreasing()) {
+			pM[0] = pM[pM.length - 1];
+			for (int i = 1; i < pM.length - 1; i++) {
+				double increasing = percentages[i] * totalDistance;
+				pM[i] = pM[i - 1] - increasing;
+			}
+		}
+		else {
+			pM[0] = pM[pM.length - 1];
+			for (int i = 1; i < pM.length - 1; i++) {
+				double decreasing = percentages[i] * totalDistance;
+				pM[i] = pM[i - 1] + decreasing;
+			}
+		}
+		pM[pM.length - 1] = pm0;
+		
+	}
+	
+	
+	/*
+	 * (non-Javadoc)
+	 * @see com.iver.cit.gvsig.fmap.core.FShapeM#setMAt(int, double)
+	 */
+	public void setMAt(int i, double value) {
+		if (i < pM.length) {
+			pM[i] = value;
+		}
+		
+	}
+	
+	
+	/*
+	 * (non-Javadoc)
+	 * @see com.iver.cit.gvsig.fmap.core.FShapeM#toText()
+	 */
+	public String toText() {
+		StringBuffer str = new StringBuffer();
+		str.append(NAME);
+		str.append(" ((");
+		int theType;
+		double[] theData = new double[6];
+		
+		PathIterator theIterator = getPathIterator(null, FConverter.FLATNESS);
+		int i = 0;
+		
+		while (!theIterator.isDone()) {
+			//while not done
+			theType = theIterator.currentSegment(theData);
+			
+			double m = 0.0;
+			if (i < pM.length) {
+				m = pM[i];
+			}
+			
+			switch (theType) {
+				case PathIterator.SEG_MOVETO:
+					str.append(theData[0] + " " + theData[1] + " " + m + ",");
+					break;
+				
+				case PathIterator.SEG_LINETO:
+					str.append(theData[0] + " " + theData[1] + " " + m + ",");
+					
+					break;
+				
+				case PathIterator.SEG_QUADTO:
+					System.out.println("Not supported here");
+					
+					break;
+				
+				case PathIterator.SEG_CUBICTO:
+					System.out.println("Not supported here");
+					
+					break;
+				
+				case PathIterator.SEG_CLOSE:
+					break;
+			} //end switch
+			
+			theIterator.next();
+			i++;
+		} //end while loop		
+		return str.delete(str.length() - 1, str.length()) + "))";
+	}
+}
Index: src/com/iver/cit/gvsig/fmap/drivers/shp/IndexedShpDriver.java
===================================================================
--- src/com/iver/cit/gvsig/fmap/drivers/shp/IndexedShpDriver.java	(revision 31709)
+++ src/com/iver/cit/gvsig/fmap/drivers/shp/IndexedShpDriver.java	(working copy)
@@ -71,6 +71,7 @@
 import com.iver.cit.gvsig.fmap.core.IGeometry;
 import com.iver.cit.gvsig.fmap.core.ShapeFactory;
 import com.iver.cit.gvsig.fmap.core.ShapeMFactory;
+import com.iver.cit.gvsig.fmap.core.ShapeZMFactory;
 import com.iver.cit.gvsig.fmap.drivers.BoundedShapes;
 import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
 import com.iver.cit.gvsig.fmap.drivers.ExternalData;
@@ -142,9 +143,8 @@
 			}
 		}
 
-		if (ret != null) {
+		if (ret != null)
 			throw ret;
-		}
 		bb = null;
 		bbShx = null;
 	}
@@ -217,19 +217,19 @@
 		shapeType = bb.getInt();
 		//el shape tal con tema tal y númro tal es null
 		if (shapeType==SHP.NULL || shapeType > 28){
-			logger.info("El shape ="+index+ " de la capa ="+this.toString()+" es null");
+			logger.info("El shape ="+index+ " de la capa ="+toString()+" es null");
 			return null;
 		}
 
 		// retrieve that shape.
 		// tempRecord.setShape(readShape(tempShapeType, tempContentLength, in));
 		switch (type) {
-			case (SHP.POINT2D):
+			case SHP.POINT2D:
 				p = readPoint(bb);
 
 				return ShapeFactory.createPoint2D(p.getX(), p.getY());
 
-			case (SHP.POLYLINE2D):
+			case SHP.POLYLINE2D:
 
 				//BoundingBox = readRectangle(bb);
 				//bb.getDouble();
@@ -259,7 +259,7 @@
 					if (i == tempParts[j]) {
 						elShape.moveTo(p.x, p.y);
 
-						if (j < (numParts - 1)) {
+						if (j < numParts - 1) {
 							j++;
 						}
 					} else {
@@ -269,7 +269,7 @@
 
 				return ShapeFactory.createPolyline2D(elShape);
 
-			case (SHP.POLYGON2D):
+			case SHP.POLYGON2D:
 
 				//	            	BoundingBox = readRectangle(bb);
 				bb.getDouble();
@@ -299,7 +299,7 @@
 					if (i == tempParts[j]) {
 						elShape.moveTo(p.x, p.y);
 
-						if (j < (numParts - 1)) {
+						if (j < numParts - 1) {
 							j++;
 						}
 					} else {
@@ -313,7 +313,7 @@
 
 				return ShapeFactory.createPolygon2D(elShape);
 
-			case (SHP.POINT3D):
+			case SHP.POINT3D:
 
 				double x = bb.getDouble();
 				double y = bb.getDouble();
@@ -321,7 +321,7 @@
 
 				return ShapeFactory.createPoint3D(x, y, z);
 
-			case (SHP.POINTM):
+			case SHP.POINTM:
 
 				double x1 = bb.getDouble();
 				double y1 = bb.getDouble();
@@ -329,7 +329,7 @@
 
 				return ShapeMFactory.createPoint2DM(x1, y1, m1);
 
-			case (SHP.POLYLINE3D):
+			case SHP.POLYLINE3D:
 				bb.position(bb.position() + 32);
 				numParts = bb.getInt();
 				numPoints = bb.getInt();
@@ -348,27 +348,40 @@
 					if (i == tempParts[j]) {
 						elShape.moveTo(p.x, p.y);
 
-						if (j < (numParts - 1)) {
+						if (j < numParts - 1) {
 							j++;
 						}
 					} else {
 						elShape.lineTo(p.x, p.y);
 					}
 				}
-
+				// read zRange
 				double[] boxZ = new double[2];
 				boxZ[0] = bb.getDouble();
 				boxZ[1] = bb.getDouble();
-
+				
+				// read zArray
 				double[] pZ = new double[numPoints];
-
 				for (i = 0; i < numPoints; i++) {
 					pZ[i] = bb.getDouble();
 				}
-
-				return ShapeFactory.createPolyline3D(elShape, pZ);
-
-			case (SHP.POLYLINEM):
+				//return ShapeFactory.createPolyline3D(elShape, pZ);
+				//------------ Piece modified -----------------
+				// read mRange
+				double[] boxM1 = new double[2];
+				boxM1[0] = bb.getDouble();//min
+				boxM1[1] = bb.getDouble();//max
+				
+				// read mArray
+				double[] pM1 = new double[numPoints];
+				for (i = 0; i < numPoints; i++) {
+					// m is optional. If "no data" --> (z < -10^-38)
+					pM1[i] = bb.getDouble();
+					//System.out.println("m: " + pM1[i]);
+				}
+				return ShapeZMFactory.createPolyline3DM(elShape, pZ, pM1);
+				//-------------------------------------
+			case SHP.POLYLINEM:
 				bb.position(bb.position() + 32);
 				numParts = bb.getInt();
 				numPoints = bb.getInt();
@@ -387,7 +400,7 @@
 					if (i == tempParts[j]) {
 						elShape.moveTo(p.x, p.y);
 
-						if (j < (numParts - 1)) {
+						if (j < numParts - 1) {
 							j++;
 						}
 					} else {
@@ -407,7 +420,7 @@
 
 				return ShapeMFactory.createPolyline2DM(elShape, pM);
 
-			case (SHP.POLYGON3D):
+			case SHP.POLYGON3D:
 			bb.position(bb.position() + 32);
 			numParts = bb.getInt();
 			numPoints = bb.getInt();
@@ -426,7 +439,7 @@
 				if (i == tempParts[j]) {
 					elShape.moveTo(p.x, p.y);
 
-					if (j < (numParts - 1)) {
+					if (j < numParts - 1) {
 						j++;
 					}
 				} else {
@@ -450,7 +463,7 @@
 
 			return ShapeFactory.createPolygon3D(elShape, poZ);
 
-			case (SHP.POLYGONM):
+			case SHP.POLYGONM:
 				bb.position(bb.position() + 32);
 				numParts = bb.getInt();
 				numPoints = bb.getInt();
@@ -469,7 +482,7 @@
 					if (i == tempParts[j]) {
 						elShape.moveTo(p.x, p.y);
 
-						if (j < (numParts - 1)) {
+						if (j < numParts - 1) {
 							j++;
 						}
 					} else {
@@ -489,7 +502,7 @@
 
 				return ShapeMFactory.createPolygon2DM(elShape, poM);
 
-			case (SHP.MULTIPOINT2D):
+			case SHP.MULTIPOINT2D:
 				bb.position(bb.position() + 32);
 				numPoints = bb.getInt();
 
@@ -503,7 +516,7 @@
 
 				return ShapeFactory.createMultipoint2D(tempX, tempY);
 
-			case (SHP.MULTIPOINT3D):
+			case SHP.MULTIPOINT3D:
 				bb.position(bb.position() + 32);
 				numPoints = bb.getInt();
 
@@ -522,7 +535,7 @@
 				}
 				return ShapeFactory.createMultipoint3D(temX, temY, temZ);
 
-			case (SHP.MULTIPOINTM):
+			case SHP.MULTIPOINTM:
 				bb.position(bb.position() + 32);
 				numPoints = bb.getInt();
 
@@ -558,43 +571,51 @@
 	public int getShapeType() {
 		int auxType = 0;
 
+		
+		// Modified to support 4D shapefiles ------------
 		switch (type) {
-			case (SHP.POINT2D):
-			case (SHP.POINT3D):
+			case SHP.POINT2D:
 				auxType = auxType | FShape.POINT;
 				break;
-
-			case (SHP.POINTM):
+			case SHP.POINTM:
 				auxType = auxType | FShape.POINT | FShape.M;
 				break;
+			case SHP.POINT3D:
+				auxType = auxType | FShape.POINT | FShape.Z;
+				break;
 
-			case (SHP.POLYLINE2D):
-			case (SHP.POLYLINE3D):
+			case SHP.POLYLINE2D:
 				auxType = auxType | FShape.LINE;
 				break;
-
-			case (SHP.POLYLINEM):
+			case SHP.POLYLINEM:
 				auxType = auxType | FShape.LINE | FShape.M;
 				break;
+			case SHP.POLYLINE3D:
+				auxType = auxType | FShape.LINE | FShape.Z;
+				break;
 
-			case (SHP.POLYGON2D):
-			case (SHP.POLYGON3D):
+			case SHP.POLYGON2D:
 				auxType = auxType | FShape.POLYGON;
 				break;
-
-			case (SHP.POLYGONM):
+			case SHP.POLYGONM:
 				auxType = auxType | FShape.POLYGON | FShape.M;
 				break;
+			case SHP.POLYGON3D:
+				auxType = auxType | FShape.POLYGON | FShape.Z;
+				break;
 
-			case (SHP.MULTIPOINT2D):
-			case (SHP.MULTIPOINT3D):
+
+			case SHP.MULTIPOINT2D:
 				auxType = auxType | FShape.MULTIPOINT;
 				break;
-
-			case (SHP.MULTIPOINTM):
+			case SHP.MULTIPOINTM:
 				auxType = auxType | FShape.MULTIPOINT | FShape.M;
 				break;
+			case SHP.MULTIPOINT3D:
+				auxType = auxType | FShape.MULTIPOINT | FShape.Z;
+				break;
 		}
+		//------------------------------------------------
 
 		return auxType;
 	}
@@ -752,11 +773,11 @@
 		}catch (Exception e) {
 			logger.error(" Shapefile is corrupted. Drawing aborted. ="+e+ "  "+"index = "+index);
 		}
-		if (bb == null) {
+		if (bb == null)
 			throw new RuntimeException("El fichero está cerrado. Revise los start() - stop() de FileDataSourceAdapater");
-		}
-		else
+		else {
 			bb.order(ByteOrder.LITTLE_ENDIAN);
+		}
 
 		int tipoShape = bb.getInt();
 
@@ -770,24 +791,24 @@
 		// retrieve that shape.
 		// tempRecord.setShape(readShape(tempShapeType, tempContentLength, in));
 		switch (tipoShape) {
-			case (SHP.POINT2D):
-			case (SHP.POINT3D):
-			case (SHP.POINTM):
+			case SHP.POINT2D:
+			case SHP.POINT3D:
+			case SHP.POINTM:
 				p = readPoint(bb);
 				BoundingBox = new Rectangle2D.Double(p.getX() - 0.1,
 						p.getY() - 0.1, 0.2, 0.2);
 
 				break;
 
-			case (SHP.POLYLINE2D):
-			case (SHP.POLYGON2D):
-			case (SHP.MULTIPOINT2D):
-			case (SHP.POLYLINE3D):
-			case (SHP.POLYGON3D):
-			case (SHP.MULTIPOINT3D):
-			case (SHP.POLYLINEM):
-			case (SHP.POLYGONM):
-			case (SHP.MULTIPOINTM):
+			case SHP.POLYLINE2D:
+			case SHP.POLYGON2D:
+			case SHP.MULTIPOINT2D:
+			case SHP.POLYLINE3D:
+			case SHP.POLYGON3D:
+			case SHP.MULTIPOINT3D:
+			case SHP.POLYLINEM:
+			case SHP.POLYGONM:
+			case SHP.MULTIPOINTM:
 
 				// BoundingBox
 				BoundingBox = readRectangle(bb);
@@ -802,7 +823,7 @@
 	 * @see com.iver.cit.gvsig.fmap.drivers.VectorialFileDriver#accept(java.io.File)
 	 */
 	public boolean accept(File f) {
-		return (f.getName().toUpperCase().endsWith("SHP"));
+		return f.getName().toUpperCase().endsWith("SHP");
 	}
 
 	/**
@@ -846,7 +867,7 @@
         // first 4 bytes are the offset
         // next 4 bytes are length
 
-        int posIndex = 100 + (numRec * 8);
+        int posIndex = 100 + numRec * 8;
         // bbShx.position(posIndex);
         long pos = 8 + 2*bbShx.getInt(posIndex);
 
Index: lib/driver-manager-1.1.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/org.gvsig.fmap.raster.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/remote-clients.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/org.gvsig.raster.gui.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/org.cresques.cts.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/org.gvsig.raster.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/jcrs.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
