Index: src/uk/me/parabola/imgfmt/app/dem/DEMFile.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/dem/DEMFile.java	(revision 4090)
+++ src/uk/me/parabola/imgfmt/app/dem/DEMFile.java	(working copy)
@@ -13,6 +13,8 @@
 
 package uk.me.parabola.imgfmt.app.dem;
 
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.List;
 
 import uk.me.parabola.imgfmt.app.Area;
@@ -19,6 +21,7 @@
 import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
 import uk.me.parabola.imgfmt.app.BufferedImgFileWriter;
 import uk.me.parabola.imgfmt.app.ImgFile;
+import uk.me.parabola.imgfmt.app.ImgFileReader;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 import uk.me.parabola.imgfmt.fs.ImgChannel;
 import uk.me.parabola.mkgmap.reader.hgt.HGTConverter;
@@ -40,7 +43,7 @@
 		setHeader(demHeader);
 		if (write) {
 			setWriter(new BufferedImgFileWriter(chan));
-			position(DEMHeader.HEADER_LEN);
+//			position(DEMHeader.HEADER_LEN);
 		} else {
 			setReader(new BufferedImgFileReader(chan));
 			demHeader.readHeader(getReader());
@@ -107,11 +110,39 @@
 		return;
 	}
 
-	public void write() {
+	private void setMaxSize() {
 		ImgFileWriter w = getWriter();
 		if (w instanceof BufferedImgFileWriter) {
 			((BufferedImgFileWriter) w).setMaxSize(0xfffffff); // increase file size limit to 256MB, no idea what the limit is
 		}
+	}
+	public void write() {
+		setMaxSize();
 		getHeader().writeHeader(getWriter());
 	}
+
+	public boolean tryCopy(ImgChannel chan, Area bounds, List<Integer> demDists) {
+		setMaxSize();
+		DEMFile old = new DEMFile(chan, false);
+		if (!old.check(bounds, demDists))
+			return false;
+		ByteBuffer buf = ByteBuffer.allocate(1024);
+		chan.position(0);
+		try {
+			while (chan.read(buf) > 0) {
+				buf.flip();
+				getWriter().put(buf);
+				buf.compact();
+			}
+			return true;
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return false;
+	}
+
+	private boolean check(Area bounds, List<Integer> demDists) {
+		return demHeader.check(bounds, demDists);
+	}
 }
Index: src/uk/me/parabola/imgfmt/app/dem/DEMHeader.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/dem/DEMHeader.java	(revision 4090)
+++ src/uk/me/parabola/imgfmt/app/dem/DEMHeader.java	(working copy)
@@ -16,6 +16,7 @@
 import java.util.List;
 
 import uk.me.parabola.imgfmt.ReadFailedException;
+import uk.me.parabola.imgfmt.app.Area;
 import uk.me.parabola.imgfmt.app.CommonHeader;
 import uk.me.parabola.imgfmt.app.ImgFileReader;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
@@ -31,7 +32,7 @@
 	private final List<DEMSection> zoomLevels = new ArrayList<>();
 	
 	private int offset;
-
+	private boolean useMeter = true;
 	public DEMHeader() {
 		super(HEADER_LEN, "GARMIN DEM");
 	}
@@ -54,8 +55,7 @@
 			zoomLevels.get(i).writeHeader(writer);
 		}
 		writer.position(pos);
-		
-		writer.putInt(0); // 0: elevation in metres, 1: foot
+		writer.putInt(useMeter ? 0:1); // 0: elevation in metres, 1: foot
 		writer.put2(zoomLevels.size());
 		writer.putInt(0); // unknown
 		writer.put2(60); // size of zoom level record
@@ -63,9 +63,21 @@
 		writer.putInt(1); // unknown, also 0 spotted
 		
 	}
-
+	
 	@Override
 	protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
+		useMeter = (reader.getInt() & 1) != 0;
+		int numLevels = reader.getUint(2);
+		reader.getInt();
+		int zoomHeaderSize = reader.getUint(2);
+		offset = reader.getInt();
+		if (zoomHeaderSize >= 60) {
+			reader.position(offset);
+			for (int i = 0; i < numLevels; i++) {
+				reader.position(offset + i * zoomHeaderSize);
+				zoomLevels.add(new DEMSection(reader, i + 1 == numLevels));
+			}
+		}
 	}
 
 
@@ -73,4 +85,53 @@
 		zoomLevels.add(section);
 	}
 
+
+	public boolean check(Area area, List<Integer> pointDistances) {
+		int top = area.getMaxLat() * 256;
+		int left = area.getMinLong() * 256;
+
+		if (zoomLevels.size() != pointDistances.size())
+			return false;
+		
+		for (int i = 0; i < zoomLevels.size(); i++) {
+			int pointDist = pointDistances.get(i);
+			DEMSection zoomLevel = zoomLevels.get(i); 
+			int distance = pointDist;
+			if (distance == -1) {
+				distance = zoomLevel.getPointDist();
+			}
+			// last 4 bits of distance should be 0
+			distance = ((distance + 8)/16)*16;
+			if (distance != zoomLevel.getPointDist())
+				return false;
+			
+			int xtop = top;
+			int xleft = left;
+
+			// align DEM to distance raster, if distance not bigger than widening of HGT area
+			if (distance < (int)Math.floor((DEMFile.EXTRA/45.0D * (1 << 29)))) {
+				if (xtop >= 0) {
+					xtop -= xtop % distance;
+					if (xtop < 0x3FFFFFFF - distance)
+						xtop += distance;
+				}
+				else {
+					xtop -= xtop % distance;
+				}
+
+				if (xleft >= 0) {
+					xleft -= xleft % distance;
+				}
+				else {
+					xleft -= xleft % distance;
+					if (xleft > Integer.MIN_VALUE + distance)
+						xleft -= distance;
+				}
+			}
+			if (xtop != zoomLevel.getTop() || xleft != zoomLevel.getLeft())
+				return false;
+
+		}
+		return true;
+	}
 }
Index: src/uk/me/parabola/imgfmt/app/dem/DEMSection.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/dem/DEMSection.java	(revision 4090)
+++ src/uk/me/parabola/imgfmt/app/dem/DEMSection.java	(working copy)
@@ -15,6 +15,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import uk.me.parabola.imgfmt.app.ImgFileReader;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.reader.hgt.HGTConverter;
@@ -25,11 +26,11 @@
 	private byte unknown1 = 0;
 	private final int zoomLevel;
 	private final boolean lastLevel;
-	private final int pointsPerLat = STD_DIM;
-	private final int pointsPerLon = STD_DIM;
+	private final int pointsPerLat;
+	private final int pointsPerLon;
 	private final int nonStdHeight;
 	private final int nonStdWidth;
-	private final short flags1 = 0;
+	private final short flags1;
 	private final int tilesLat;
 	private final int tilesLon;
 	private int offsetSize;
@@ -53,7 +54,9 @@
 		
 		this.top = areaTop;
 		this.left = areaLeft;
-
+		this.pointsPerLat = STD_DIM;
+		this.pointsPerLon = STD_DIM;
+		
 		// calculate raster that starts at top left corner
 		// last row and right column have non-standard height / row values 
 		pointsDistanceLat = pointDist; 
@@ -69,11 +72,42 @@
 		tilesLon = lonInfo[0];
 		nonStdHeight = latInfo[1];
 		nonStdWidth = lonInfo[1];
+		flags1 = 0;
 		log.info("calculating zoom level:",zoomLevel,", dist:",pointDist,tilesLon,"x",tilesLat,"std tiles, nonstd x/y",nonStdWidth,"/",nonStdHeight);
 		calcTiles(hgtConverter);
-		hgtConverter = null;
 	}
 
+	public DEMSection (ImgFileReader reader, boolean lastLevel) {
+		this.lastLevel = lastLevel;
+
+		unknown1 = reader.get();//0x00
+		zoomLevel = reader.getUint(1); //0x01
+		pointsPerLat = reader.getInt(); //0x02 
+		pointsPerLon = reader.getInt(); //0x06 
+		nonStdHeight = reader.getInt() + 1; //0x0A
+		nonStdWidth = reader.getInt() + 1;	//0x0E 
+		flags1 = (short) reader.getUint(2);	//0x12
+		tilesLon  = reader.getInt() + 1;	//0x14
+		tilesLat = reader.getInt() + 1;	//0x18
+		int recordDesc = reader.getUint(2);//0x1c
+		offsetSize = (recordDesc & 3) + 1;
+		baseSize = ((recordDesc & 4) >> 2) + 1;
+		differenceSize = ((recordDesc & 8) >> 3) + 1;
+		hasExtra = (recordDesc & 0x10) != 0;		
+		
+		tileDescSize = reader.getUint(2);	//0x1e
+		dataOffset = reader.getInt();	//0x20
+		dataOffset2 = reader.getInt();	//0x24
+		left = reader.getInt();	//0x28 
+		top = reader.getInt();	//0x2c 
+		pointsDistanceLat = reader.getInt();;	//0x30
+		pointsDistanceLon = reader.getInt();;	//0x34
+		minHeight = reader.getChar();//0x38
+		maxHeight = reader.getChar();;	//0x3a
+		assert minHeight >= Short.MIN_VALUE && minHeight <= Short.MAX_VALUE; 
+		assert maxHeight >= Short.MIN_VALUE && maxHeight <= Short.MAX_VALUE; 
+	}
+
 	/**
 	 * Calculate the number of rows / columns and the non-standard height/width 
 	 * @param demPoints number of 32 bit points 
@@ -100,6 +134,7 @@
 		int[] res = {num, nonstd};
 		return res;
 	}
+	
 	private void calcTiles(HGTConverter hgtConverter) {
 		int resLon = pointsPerLon * pointsDistanceLon;
 		int resLat = pointsPerLat * pointsDistanceLat;
@@ -246,5 +281,18 @@
 	public boolean hasExtra() {
 		return hasExtra;
 	}
+
+	public int getPointDist() {
+		assert pointsDistanceLat == pointsDistanceLon;
+		return pointsDistanceLat;
+	}
+
+	public int getTop() {
+		return top;
+	}
+
+	public int getLeft() {
+		return left;
+	}
 }
 
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/MapBuilder.java	(revision 4090)
+++ src/uk/me/parabola/mkgmap/build/MapBuilder.java	(working copy)
@@ -16,6 +16,7 @@
 import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.time.LocalDateTime;
@@ -67,6 +68,11 @@
 import uk.me.parabola.imgfmt.app.trergn.Subdivision;
 import uk.me.parabola.imgfmt.app.trergn.TREFile;
 import uk.me.parabola.imgfmt.app.trergn.Zoom;
+import uk.me.parabola.imgfmt.fs.DirectoryEntry;
+import uk.me.parabola.imgfmt.fs.FileSystem;
+import uk.me.parabola.imgfmt.fs.ImgChannel;
+import uk.me.parabola.imgfmt.sys.FileImgChannel;
+import uk.me.parabola.imgfmt.sys.ImgFS;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.Version;
 import uk.me.parabola.mkgmap.combiners.OverviewBuilder;
@@ -168,6 +174,7 @@
 	private short demOutsidePolygonHeight;
 	private java.awt.geom.Area demPolygon;
 	private HGTConverter.InterpolationMethod demInterpolationMethod;
+	private String demReuseDir;
 	
 
 	public MapBuilder() {
@@ -234,6 +241,7 @@
 			throw new IllegalArgumentException("invalid argument for option dem-interpolation: '" + ipm + 
 					"' supported are 'bilinear', 'bicubic', or 'auto'");
 		}
+		demReuseDir =  props.getProperty("dem-reuse", null);
 	}
 
 	private List<Integer> parseDemDists(String demDists) {
@@ -318,36 +326,101 @@
 			}
 			netFile.writePost(rgnFile.getWriter());
 		}
+		warnAbout3ByteImgRefs();
+		
 		if (demFile != null) {
-			try{
-				long t1 = System.currentTimeMillis();
-				java.awt.geom.Area  demArea = null;
-				if (demPolygon != null) {
-					Area bbox = src.getBounds();
-					// the rectangle is a bit larger to avoid problems at tile boundaries
-					Rectangle2D r = new Rectangle2D.Double(bbox.getMinLong() - 2, bbox.getMinLat() - 2,
-							bbox.getWidth() + 4, bbox.getHeight() + 4);
-					demArea = new java.awt.geom.Area(r);
-					demArea.intersect(demPolygon);
-				} 
-				if (demArea == null && src instanceof OverviewMapDataSource) {
-					Path2D demPoly = ((OverviewMapDataSource) src).getTileAreaPath();
-					if (demPoly != null) {
-						demArea = new java.awt.geom.Area(demPoly);
+			boolean calc = true;
+			if (demReuseDir != null && src instanceof OverviewMapDataSource == false) {
+				File f = new File(demReuseDir);
+				String mapName = new File(map.getFilename()).getName().replace(".img","");
+				String demFilename = mapName + ".DEM";
+					
+				ImgChannel chan = null;
+				if (f.isFile() && demReuseDir.endsWith(".img")) {
+					// try to extract dem from single file img , e.g. gmapsupp.img
+					try {
+						FileSystem fs = ImgFS.openFs(demReuseDir);
+						chan = extractDem(fs, demFilename);
+					} catch (FileNotFoundException e) {
 					}
+				} else if (f.isDirectory()) {
+					try {
+						if (demReuseDir.endsWith(".gmap")) {
+							String[] files = f.list();
+							for (String dir : files) {
+								if (dir.toLowerCase().startsWith("product")) {
+									String demPath = Utils.joinPath(demReuseDir, dir);
+									demPath = Utils.joinPath(demPath, mapName);
+									demPath = Utils.joinPath(demPath, demFilename);
+									chan = new FileImgChannel(demPath, "r");
+									if (chan != null)
+										break;
+								}
+							}
+						} else {
+							String imgName = Utils.joinPath(demReuseDir, mapName, "img");
+							FileSystem fs = ImgFS.openFs(imgName);
+							chan = extractDem(fs, demFilename);
+						}
+					} catch (FileNotFoundException e) {
+					}
 				}
-				demFile.calc(src.getBounds(), demArea, pathToHGT, demDists, demOutsidePolygonHeight, demInterpolationMethod);
-				long t2 = System.currentTimeMillis();
-				log.info("DEM file calculation for", map.getFilename(), "took", (t2 - t1), "ms");
-				demFile.write();
-			} catch (MapFailedException e) {
-				log.error("exception while creating DEM file", e.getMessage());
-				throw new MapFailedException("DEM"); //TODO: better remove DEM file?
+				if (chan != null) {
+					if (demFile.tryCopy(chan, src.getBounds(), demDists))
+						calc = false;
+					else {
+						log.warn(demFilename,"in",demReuseDir,"was created for different bounds or different dem-dists");
+					}
+					
+				} else {
+					log.warn(demReuseDir, "doesn't contain expected file", demFilename);
+				}
+				
 			}
+			if (calc) {
+				calcDem(demFile, src);
+			}
 		}
-		warnAbout3ByteImgRefs();
 	}
 
+	private ImgChannel extractDem(FileSystem fs, String filename) throws FileNotFoundException {
+		List<DirectoryEntry> entries = fs.list();
+		for (DirectoryEntry ent : entries) {
+			if (filename.equals(ent.getFullName())) {
+				return fs.open(ent.getFullName(), "r");
+			}
+		}
+		return null;
+	}
+
+	private void calcDem(DEMFile demFile, LoadableMapDataSource src) {
+		try{
+			long t1 = System.currentTimeMillis();
+			java.awt.geom.Area  demArea = null;
+			if (demPolygon != null) {
+				Area bbox = src.getBounds();
+				// the rectangle is a bit larger to avoid problems at tile boundaries
+				Rectangle2D r = new Rectangle2D.Double(bbox.getMinLong() - 2, bbox.getMinLat() - 2,
+						bbox.getWidth() + 4, bbox.getHeight() + 4);
+				demArea = new java.awt.geom.Area(r);
+				demArea.intersect(demPolygon);
+			} 
+			if (demArea == null && src instanceof OverviewMapDataSource) {
+				Path2D demPoly = ((OverviewMapDataSource) src).getTileAreaPath();
+				if (demPoly != null) {
+					demArea = new java.awt.geom.Area(demPoly);
+				}
+			}
+			demFile.calc(src.getBounds(), demArea, pathToHGT, demDists, demOutsidePolygonHeight, demInterpolationMethod);
+			long t2 = System.currentTimeMillis();
+			log.info("DEM file calculation took", (t2 - t1), "ms");
+			demFile.write();
+		} catch (MapFailedException e) {
+			log.error("exception while creating DEM file", e.getMessage());
+			throw new MapFailedException("DEM"); //TODO: better remove DEM file?
+		}
+	}
+	
 	private void warnAbout3ByteImgRefs() {
 		String infoMsg = "- more than 65535 might cause indexing problems and excess size. Suggest splitter with lower --max-nodes";
 		int itemCount;
