diff --git a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
index 7323017..1238a5f 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
@@ -122,6 +122,8 @@ public class RoadDef implements Comparable {
 
 	private City city;
 	private Zip zip;
+	private boolean paved = true;
+	private boolean ferry = false;
 	private boolean roundabout;
 	private boolean linkRoad;
 	private boolean synthesised;
@@ -586,6 +588,22 @@ public class RoadDef implements Comparable {
 		return city;
 	}
 
+	public boolean paved() {
+		return paved;
+	}
+
+	public void paved(boolean p) {
+		paved = p;
+	}
+
+	public void ferry(boolean f) {
+		ferry = f;
+	}
+
+	public boolean ferry() {
+		return ferry;
+	}
+
 	public void setRoundabout(boolean r) {
 		roundabout = r;
 	}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java b/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
index a4134c4..3fc632f 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
@@ -47,7 +47,7 @@ public class RouteCenter {
 		this.nodes = nodes;
 		this.tabA = tabA;
 		this.tabB = tabB;
-		this.tabC = new TableC();
+		this.tabC = new TableC(tabA);
 
 		log.info("new RouteCenter at " + centralPoint.toDegreeString() +
 				 ", nodes: " + nodes.size()	+ " tabA: " + tabA.size() +
@@ -106,7 +106,7 @@ public class RouteCenter {
 		writer.position(tablesOffset);
 
 		// Write the tables header
-		writer.put(tabC.getSizeBytes());
+		writer.put(tabC.getFormat());
 		writer.put3(centralPoint.getLongitude());
 		writer.put3(centralPoint.getLatitude());
 		writer.put(tabA.getNumberOfItems());
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableA.java b/src/uk/me/parabola/imgfmt/app/net/TableA.java
index a0c87ee..9ae5a9a 100644
--- a/src/uk/me/parabola/imgfmt/app/net/TableA.java
+++ b/src/uk/me/parabola/imgfmt/app/net/TableA.java
@@ -16,6 +16,7 @@
  */
 package uk.me.parabola.imgfmt.app.net;
 
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
@@ -37,10 +38,17 @@ public class TableA {
 	// This table's start position relative to the start of NOD 1
 	private int offset;
 
-	private final LinkedHashMap<Arc,Integer> arcs = new LinkedHashMap<Arc,Integer>();
+	// arcs for paved ways
+	private final HashMap<Arc,Integer> pavedArcs = new LinkedHashMap<Arc,Integer>();
+	// arcs for unpaved ways
+	private final HashMap<Arc,Integer> unpavedArcs = new LinkedHashMap<Arc,Integer>();
+	// arcs for ferry ways
+	private final HashMap<Arc,Integer> ferryArcs = new LinkedHashMap<Arc,Integer>();
 
 	private static int count;
 
+	private boolean frozen = false; // true when no more arcs should be added
+
 	public TableA() {
 		log.debug("creating TableA", count);
 		count++;
@@ -88,24 +96,54 @@ public class TableA {
 	 * the table fulfills the size constraint.
 	 */
 	public void addArc(RouteArc arc) {
+		assert !frozen : "trying to add arc to Table A after it has been frozen";
 		Arc narc = new Arc(arc);
 		int i;
-		if (!arcs.containsKey(narc)) {
-			i = arcs.size();
-			arcs.put(narc, i);
-			log.debug("added arc", count, narc, i);
+		if(arc.getRoadDef().ferry()) {
+			if (!ferryArcs.containsKey(narc)) {
+				i = ferryArcs.size();
+				ferryArcs.put(narc, i);
+				log.debug("added ferry arc", count, narc, i);
+			}
+		}
+		else if(arc.getRoadDef().paved()) {
+			if (!pavedArcs.containsKey(narc)) {
+				i = pavedArcs.size();
+				pavedArcs.put(narc, i);
+				log.debug("added paved arc", count, narc, i);
+			}
+		}
+		else {
+			if (!unpavedArcs.containsKey(narc)) {
+				i = unpavedArcs.size();
+				unpavedArcs.put(narc, i);
+				log.debug("added unpaved arc", count, narc, i);
+			}
 		}
 	}
 
 	/**
-	 * Retrieve an arc's index.
+	 * Retrieve an arc's index (unpaved arcs are all before the paved arcs)
 	 */
 	public byte getIndex(RouteArc arc) {
-		log.debug("getting index", arc);
+		frozen = true;
 		Arc narc = new Arc(arc);
-		assert arcs.containsKey(narc):
+		int i;
+		if(arc.getRoadDef().ferry()) {
+			assert ferryArcs.containsKey(narc):
+			"Trying to read Table A index for non-registered arc: " + count + " " + narc;
+			i = unpavedArcs.size() + ferryArcs.get(narc);
+		}
+		else if(arc.getRoadDef().paved()) {
+			assert pavedArcs.containsKey(narc):
+			"Trying to read Table A index for non-registered arc: " + count + " " + narc;
+			i = unpavedArcs.size() + ferryArcs.size() + pavedArcs.get(narc);
+		}
+		else {
+			assert unpavedArcs.containsKey(narc):
 			"Trying to read Table A index for non-registered arc: " + count + " " + narc;
-		int i = arcs.get(narc);
+			i = unpavedArcs.get(narc);
+		}
 		assert i < 0x100 : "Table A index too large: " + narc;
 		return (byte) i;
 	}
@@ -118,7 +156,15 @@ public class TableA {
 	 * the network.
 	 */
 	public int size() {
-		return arcs.size();
+		return ferryArcs.size() + unpavedArcs.size() + pavedArcs.size();
+	}
+
+	public int numUnpavedArcs() {
+		return unpavedArcs.size();
+	}
+
+	public int numFerryArcs() {
+		return ferryArcs.size();
 	}
 
 	/**
@@ -130,8 +176,8 @@ public class TableA {
 	 * it isn't too large.
 	 */
 	public byte getNumberOfItems() {
-		assert arcs.size() < 0x100 : "Table A too large";
-		return (byte) arcs.size();
+		assert size() < 0x100 : "Table A too large";
+		return (byte)size();
 	}
 
 	/**
@@ -140,7 +186,7 @@ public class TableA {
 	 */
 	public void write(ImgFileWriter writer) {
 		offset = writer.position();
-		int size = arcs.size() * ITEM_SIZE;		
+		int size = size() * ITEM_SIZE;
 		log.debug("tab a offset", offset, "tab a size", size);
 	
 		for (int i = 0; i < size; i++)
@@ -152,19 +198,31 @@ public class TableA {
 	 */
 	public void writePost(ImgFileWriter writer) {
 		writer.position(offset);
-		for (Arc arc : arcs.keySet()) {
-			// write the table A entries.  Consists of a pointer to net
-			// followed by 2 bytes of class and speed flags and road restrictions.
-			log.debug("writing Table A entry", arcs.get(arc));
-			int pos = arc.roadDef.getOffsetNet1();
-			int access = arc.roadDef.getTabAAccess();
-			// top bits of access go into net1 offset
-			final int ACCESS_TOP_BITS = 0xc000;
-			pos |= (access & ACCESS_TOP_BITS) << 8;
-			access &= ~ACCESS_TOP_BITS;
-			writer.put3(pos);
-			writer.put((byte) arc.roadDef.getTabAInfo());
-			writer.put((byte) access);
+		// unpaved arcs first
+		for (Arc arc : unpavedArcs.keySet()) {
+			writePost(writer, arc);
+		}
+		// followed by the ferry arcs
+		for (Arc arc : ferryArcs.keySet()) {
+			writePost(writer, arc);
+		}
+		// followed by the paved arcs
+		for (Arc arc : pavedArcs.keySet()) {
+			writePost(writer, arc);
 		}
 	}
+
+	public void writePost(ImgFileWriter writer, Arc arc) {
+		// write the table A entries.  Consists of a pointer to net
+		// followed by 2 bytes of class and speed flags and road restrictions.
+		int pos = arc.roadDef.getOffsetNet1();
+		int access = arc.roadDef.getTabAAccess();
+		// top bits of access go into net1 offset
+		final int ACCESS_TOP_BITS = 0xc000;
+		pos |= (access & ACCESS_TOP_BITS) << 8;
+		access &= ~ACCESS_TOP_BITS;
+		writer.put3(pos);
+		writer.put((byte) arc.roadDef.getTabAInfo());
+		writer.put((byte) access);
+	}
 }
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableC.java b/src/uk/me/parabola/imgfmt/app/net/TableC.java
index 5cd9992..62f96d9 100644
--- a/src/uk/me/parabola/imgfmt/app/net/TableC.java
+++ b/src/uk/me/parabola/imgfmt/app/net/TableC.java
@@ -29,25 +29,39 @@ public class TableC {
 	// size of the table, excluding the size field
 	private int size;
 
+	private final TableA tabA;
+
 	private final List<RouteRestriction> restrictions = new ArrayList<RouteRestriction>();
 
+	public TableC(TableA tabA) {
+		this.tabA = tabA;
+	}
+
 	/**
 	 * Write the table including size field.
 	 */
 	public void write(ImgFileWriter writer, int tablesOffset) {
 		if (restrictions.isEmpty()) {
+			if(tabA.numUnpavedArcs() > 0)
+				writer.put((byte)tabA.numUnpavedArcs());
+			if(tabA.numFerryArcs() > 0)
+				writer.put((byte)tabA.numFerryArcs());
 			writer.put((byte) 0);
-			return;
-		} else {
+		}
+		else {
 			byte b = getSizeBytes();
 			assert size < (1 << 8*b);
 			if (b == 1)
 				writer.put((byte) size);
 			else
 				writer.putChar((char) size);
+			for (RouteRestriction restr : restrictions)
+				restr.write(writer, tablesOffset);
+			if(tabA.numUnpavedArcs() > 0)
+				writer.put((byte)tabA.numUnpavedArcs());
+			if(tabA.numFerryArcs() > 0)
+				writer.put((byte)tabA.numFerryArcs());
 		}
-		for (RouteRestriction restr : restrictions)
-			restr.write(writer, tablesOffset);
 	}
 
 	/**
@@ -85,4 +99,13 @@ public class TableC {
 		for (RouteRestriction restr : restrictions)
 			restr.setOffsetSize(b);
 	}
+
+	public byte getFormat() {
+		byte format = getSizeBytes();
+		if(tabA.numUnpavedArcs() > 0)
+			format |= 0x08;
+		if(tabA.numFerryArcs() > 0)
+			format |= 0x10;
+		return format;
+	}
 }
diff --git a/src/uk/me/parabola/mkgmap/general/MapRoad.java b/src/uk/me/parabola/mkgmap/general/MapRoad.java
index c540a69..3703ad2 100644
--- a/src/uk/me/parabola/mkgmap/general/MapRoad.java
+++ b/src/uk/me/parabola/mkgmap/general/MapRoad.java
@@ -72,6 +72,14 @@ public class MapRoad extends MapLine {
 		this.roadDef.setToll();
 	}
 
+	public void paved(boolean p) {
+		this.roadDef.paved(p);
+	}
+
+	public void ferry(boolean f) {
+		this.roadDef.ferry(f);
+	}
+
 	public void showOSMBrowseURL() {
 		this.roadDef.showOSMBrowseURL();
 	}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index fbff7e0..0e9d37f 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -1426,6 +1426,14 @@ public class StyledConverter implements OsmConverter {
 		if(way.isBoolTag("toll"))
 			road.setToll();
 
+		// assume road is paved unless unpaved tag is true or paved
+		// tag is false, in which case, consider road as unpaved
+		if(way.isBoolTag("unpaved") || way.isNotBoolTag("paved"))
+			road.paved(false);
+
+		if("ferry".equals(way.getTag("route")))
+			road.ferry(true);
+
 		Way origWay = originalWay.get(way);
 		if(origWay == null)
 			origWay = way;
