diff --git a/resources/styles/default/points b/resources/styles/default/points
index aaf9267..843f188 100644
--- a/resources/styles/default/points
+++ b/resources/styles/default/points
@@ -36,6 +36,12 @@ amenity=zoo [0x2c07 resolution 21]
 
 highway=bus_stop [0x2f08 resolution 21]
 
+highway=motorway_junction { name '${ref} ${name}' | '${ref}' | '${name}' }
+highway=motorway_junction [0x2000 resolution 16]
+
+highway=services { name '${ref} ${name}' | '${ref}' | '${name}' }
+highway=services [0x210f resolution 16]
+
 historic=museum [0x2c02 resolution 20]
 historic=archaeological_site [0x2c02 resolution 21]
 
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/ExitFacility.java b/src/uk/me/parabola/imgfmt/app/lbl/ExitFacility.java
new file mode 100644
index 0000000..9cc5f71
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/ExitFacility.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 Steve Ratcliffe
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *
+ * Author: Steve Ratcliffe
+ * Create date: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * Represent a facility at a motorway exit
+ *
+ * @author Mark Burton
+ */
+public class ExitFacility {
+
+	private final int index;
+	private Label description;
+	private	int type;	// truck stop - 24 hour diesel + food
+	private	int direction;	// undefined
+	private	int facilities;	// none
+	private boolean last;
+
+	public ExitFacility(int type, char direction, int facilities, Label description, boolean last, int index) {
+		this.type = type;
+		this.direction = directionCode(direction);
+		this.facilities = facilities;
+		this.description = description;
+		this.last = last;
+		this.index = index;
+	}
+
+	void write(ImgFileWriter writer) {
+		int word = 0;
+		word |= description.getOffset(); // 0:21 = label offset
+		// 22 = unknown
+		if(last)
+			word |= 1 << 23; // 23 = last facility for this exit
+		word |= type << 24;	 // 24:27 = 4 bit type
+		// 28 = unknown
+		word |= direction << 29; // 29:31 = 3 bit direction
+		writer.putChar((char)word);
+		writer.putChar((char)(word >> 16));
+		writer.put((byte)facilities);
+	}
+
+	public int getIndex() {
+		return index;
+	}
+
+	public boolean getOvernightParking() {
+		return false;
+	}
+
+	private int directionCode(char direction) {
+		int code = "NSEWIOB".indexOf(direction);
+		if(code < 0)
+			code = 7; // undefined
+		return code;
+	}
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/Highway.java b/src/uk/me/parabola/imgfmt/app/lbl/Highway.java
new file mode 100644
index 0000000..68c4b99
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/Highway.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 Steve Ratcliffe
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *
+ * Author: Steve Ratcliffe
+ * Create date: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.Label;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * A highway is in a region.
+ *
+ * @author Mark Burton
+ */
+public class Highway {
+
+	private final int index;
+
+	private final Region region;
+
+	private Label label;
+
+	public Highway(Region region, int index) {
+		this.region = region;
+		this.index = index;
+	}
+
+	void write(ImgFileWriter writer, boolean extraData) {
+		if(extraData) {
+			writer.put((byte)0); // unknown
+			writer.putChar((char)region.getIndex());
+		}
+		else {
+			writer.put3(label.getOffset());
+			writer.putChar((char)((index - 1) * PlacesHeader.HIGHWAYDATA_REC_LEN + 1));
+			writer.put((byte)0); // unknown
+		}
+	}
+
+	public int getIndex() {
+		return index;
+	}
+
+	public Region getRegion() {
+		return region;
+	}
+
+	public void setLabel(Label label) {
+		this.label = label;
+	}
+
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java b/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java
index 40a5529..f01389a 100644
--- a/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java
+++ b/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java
@@ -30,8 +30,10 @@ import uk.me.parabola.imgfmt.app.labelenc.CharacterDecoder;
 import uk.me.parabola.imgfmt.app.labelenc.CharacterEncoder;
 import uk.me.parabola.imgfmt.app.labelenc.CodeFunctions;
 import uk.me.parabola.imgfmt.app.labelenc.EncodedText;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
 import uk.me.parabola.imgfmt.fs.ImgChannel;
 import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.Exit;
 
 /**
  * The file that holds all the labels for the map.
@@ -138,6 +140,14 @@ public class LBLFile extends ImgFile {
 	public POIRecord createPOI(String name) {
 		return places.createPOI(name);
 	}
+
+	public POIRecord createExitPOI(String name, Exit exit) {
+		return places.createExitPOI(name, exit);
+	}
+
+	public POIIndex createPOIIndex(String name, int poiIndex, Subdivision group, int type) {
+		return places.createPOIIndex(name, poiIndex, group, type);
+	}
 	
 	public Country createCountry(String name, String abbr) {
 		return places.createCountry(name, abbr);
@@ -159,6 +169,14 @@ public class LBLFile extends ImgFile {
 		return places.createZip(code);
 	}
 
+	public Highway createHighway(Region region, String name) {
+		return places.createHighway(region, name);
+	}
+
+	public ExitFacility createExitFacility(int type, char direction, int facilities, String description, boolean last) {
+		return places.createExitFacility(type, direction, facilities, description, last);
+	}
+
 	public void allPOIsDone() {
 		places.allPOIsDone();
 	}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/POIIndex.java b/src/uk/me/parabola/imgfmt/app/lbl/POIIndex.java
new file mode 100644
index 0000000..340a444
--- /dev/null
+++ b/src/uk/me/parabola/imgfmt/app/lbl/POIIndex.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Steve Ratcliffe
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ * 
+ * Author: Steve Ratcliffe
+ * Create date: Jan 1, 2008
+ */
+package uk.me.parabola.imgfmt.app.lbl;
+
+import uk.me.parabola.imgfmt.app.ImgFileWriter;
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
+/**
+ * Represent a POI index entry
+ * 
+ * @author Mark Burton
+ */
+public class POIIndex implements Comparable {
+
+	private final String name;
+	private final byte poiIndex;
+	private final Subdivision group;
+	private final byte subType;
+
+	public POIIndex(String name, byte poiIndex, Subdivision group, byte subType) {
+		this.name = name;
+		this.poiIndex = poiIndex;
+		this.group = group;
+		this.subType = subType;
+	}
+
+	void write(ImgFileWriter writer) {
+		writer.put(poiIndex);
+		writer.putChar((char)group.getNumber());
+		writer.put(subType);
+		//System.err.println("Writing POI Index " + name + " group = " + group.getNumber());
+	}
+
+	public int compareTo(Object o) {
+		return name.compareTo(((POIIndex)o).name);
+	}
+}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java b/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
index 24115a3..036a69f 100644
--- a/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
+++ b/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
@@ -16,9 +16,13 @@
  */
 package uk.me.parabola.imgfmt.app.lbl;
 
+import java.util.List;
+
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 import uk.me.parabola.imgfmt.app.Label;
 
+import uk.me.parabola.mkgmap.general.Exit;
+
 /**
  * @author Steve Ratcliffe
  */
@@ -142,6 +146,7 @@ public class POIRecord {
 	
 	private City city;
 	private char zipIndex;
+	private Exit exit;
 
 	//private String phoneNumber;
 
@@ -184,10 +189,13 @@ public class POIRecord {
 		this.city = city;
 	}
 
-	void write(ImgFileWriter writer, byte POIGlobalFlags, int realofs,
-		   long numCities, long numZips) {
-		assert offset == realofs;
+	public void setExit(Exit exit) {
+		this.exit = exit;
+	}
 
+	void write(ImgFileWriter writer, byte POIGlobalFlags, int realofs,
+		   long numCities, long numZips, long numHighways, long numExitFacilities) {
+		assert offset == realofs : "offset = " + offset + " realofs = " + realofs;
 		int ptr = poiName.getOffset();
 		if (POIGlobalFlags != getPOIFlags())
 			ptr |= 0x800000;
@@ -207,7 +215,7 @@ public class POIRecord {
 
 		if (streetName != null)
 			writer.put3(streetName.getOffset());
-			
+
 		if (city != null)
 		{
 			char cityIndex = (char) city.getIndex();
@@ -216,7 +224,7 @@ public class POIRecord {
 			else
 				writer.put((byte)cityIndex);
 		}
-			
+
 		if (zipIndex > 0)
 		{
 			if(numZips > 255)
@@ -224,7 +232,7 @@ public class POIRecord {
 			else
 				writer.put((byte)zipIndex);
 		}
-		
+
 		if (complexPhoneNumber != null)
 		{
 			int labOff = complexPhoneNumber.getOffset();
@@ -233,6 +241,36 @@ public class POIRecord {
 		}
 		else if (simplePhoneNumber.isUsed())
 			simplePhoneNumber.write(writer);
+
+		if(exit != null) {
+			Label description = exit.getDescription();
+			int val = 0;
+			if(description != null) {
+				val = description.getOffset();
+				assert val < 0x400000 : "Exit description label offset too large";
+			}
+			if(exit.getOvernightParking())
+				val |= 0x400000;
+			List<ExitFacility> facilites = exit.getFacilities();
+			ExitFacility ef = null;
+			if(facilites.size() > 0)
+				ef = facilites.get(0);
+			char exitFacilityIndex = 0;
+			if(ef != null) {
+				exitFacilityIndex = (char)ef.getIndex();
+				val |= 0x800000; // exit facilites defined
+			}
+			writer.put3(val);
+			char highwayIndex = (char)exit.getHighway().getIndex();
+			if(numHighways > 255)
+				writer.putChar(highwayIndex);
+			else
+				writer.put((byte)highwayIndex);
+			if(numExitFacilities > 255)
+				writer.putChar(exitFacilityIndex);
+			else
+				writer.put((byte)exitFacilityIndex);
+		}
 	}
 
 	byte getPOIFlags() {
@@ -240,13 +278,15 @@ public class POIRecord {
 		if (streetName != null)
 			b |= HAS_STREET;
 		if (simpleStreetNumber.isUsed() || streetNumberName != null)
-		   b |= HAS_STREET_NUM;
+			b |= HAS_STREET_NUM;
 		if (city != null)
 		        b |= HAS_CITY;
 		if (zipIndex > 0)
-		        b |= HAS_ZIP;	
+		        b |= HAS_ZIP;
 		if (simplePhoneNumber.isUsed() || complexPhoneNumber != null)
-		   b |= HAS_PHONE;				  		
+			b |= HAS_PHONE;
+		if (exit != null)
+			b |= HAS_EXIT;
 		return b;
 	}
 	
@@ -285,9 +325,14 @@ public class POIRecord {
 	 *
 	 * \return Number of bytes needed by this entry
 	 */
-	int calcOffset(int ofs, byte POIGlobalFlags, long numCities, long numZips) {
+	int calcOffset(int ofs, byte POIGlobalFlags, long numCities, long numZips, long numHighways, long numExitFacilities) {
 		offset = ofs;
 		int size = 3;
+		if (exit != null) {
+		    size += 3;
+		    size += (numHighways > 255)? 2 : 1;
+		    size += (numExitFacilities > 255)? 2 : 1;
+		}
 		if (POIGlobalFlags != getPOIFlags())
 			size += 1;
 		if (simpleStreetNumber.isUsed())		
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java b/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java
index 7f5e6bf..c546616 100644
--- a/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java
+++ b/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java
@@ -23,9 +23,13 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import uk.me.parabola.imgfmt.app.trergn.Subdivision;
+
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 import uk.me.parabola.imgfmt.app.Label;
 
+import uk.me.parabola.mkgmap.general.Exit;
+
 /**
  * This is really part of the LBLFile.  We split out all the parts of the file
  * that are to do with location to here.
@@ -36,7 +40,10 @@ public class PlacesFile {
 	private final Map<String, City> cities = new LinkedHashMap<String, City>();
 	private final List<CitySort> cityList = new ArrayList<CitySort>();
 	private final Map<String, Zip> postalCodes = new LinkedHashMap<String, Zip>();
+	private final List<Highway> highways = new ArrayList<Highway>();
+	private final List<ExitFacility> exitFacilities = new ArrayList<ExitFacility>();
 	private final List<POIRecord> pois = new ArrayList<POIRecord>();
+	private final List[] poiIndex = new ArrayList[256];
 
 	private LBLFile lblFile;
 	private PlacesHeader placeHeader;
@@ -71,16 +78,48 @@ public class PlacesFile {
 
 		placeHeader.endCity(writer.position());
 
+		for (List<POIIndex> pil : poiIndex) {
+			if(pil != null) {
+				// sort entries by POI name
+				Collections.sort(pil);
+			    	for(POIIndex pi : pil)
+					pi.write(writer);
+			}
+		}
+		placeHeader.endPOIIndex(writer.position());
+
 		int poistart = writer.position();
 		byte poiglobalflags = placeHeader.getPOIGlobalFlags();
 		for (POIRecord p : pois)
 			p.write(writer, poiglobalflags,
-				writer.position() - poistart, cities.size(), postalCodes.size());
+				writer.position() - poistart, cities.size(), postalCodes.size(), highways.size(), exitFacilities.size());
 		placeHeader.endPOI(writer.position());
 
+		int numPoiIndexEntries = 0;
+		for (int i = 0; i < 256; ++i) {
+			if(poiIndex[i] != null) {
+				writer.put((byte)i);
+				writer.put3(numPoiIndexEntries + 1);
+				numPoiIndexEntries += poiIndex[i].size();
+			}
+		}
+		placeHeader.endPOITypeIndex(writer.position());
+
 		for (Zip z : postalCodes.values())
 			z.write(writer);
 		placeHeader.endZip(writer.position());
+
+		for (Highway h : highways)
+			h.write(writer, false);
+		placeHeader.endHighway(writer.position());
+
+		for (ExitFacility ef : exitFacilities)
+			ef.write(writer);
+		placeHeader.endExitFacility(writer.position());
+
+		for (Highway h : highways)
+			h.write(writer, true);
+		placeHeader.endHighwayData(writer.position());
 	}
 
 	Country createCountry(String name, String abbr) {
@@ -193,6 +232,23 @@ public class PlacesFile {
 		return z;
 	}
 
+	Highway createHighway(Region region, String name) {
+		Highway h = new Highway(region, highways.size()+1);
+
+		Label l = lblFile.newLabel(name);
+		h.setLabel(l);
+
+		highways.add(h);
+		return h;
+	}
+
+	public ExitFacility createExitFacility(int type, char direction, int facilities, String description, boolean last) {
+		Label d = lblFile.newLabel(description);
+		ExitFacility ef = new ExitFacility(type, direction, facilities, d, last, exitFacilities.size()+1);
+		exitFacilities.add(ef);
+		return ef;
+	}
+
 	POIRecord createPOI(String name) {
 		assert !poisClosed;
 		// TODO...
@@ -206,6 +262,31 @@ public class PlacesFile {
 		return p;
 	}
 
+	POIRecord createExitPOI(String name, Exit exit) {
+		assert !poisClosed;
+		// TODO...
+		POIRecord p = new POIRecord();
+
+		Label l = lblFile.newLabel(name);
+		p.setLabel(l);
+
+		p.setExit(exit);
+
+		pois.add(p);
+		
+		return p;
+	}
+
+	POIIndex createPOIIndex(String name, int index, Subdivision group, int type) {
+		assert index < 0x100 : "Too many POIS in division";
+		POIIndex pi = new POIIndex(name, (byte)index, group, (byte)type);
+		int t = type >> 8;
+		if(poiIndex[t] == null)
+			poiIndex[t] = new ArrayList<POIIndex>();
+		poiIndex[t].add(pi);
+		return pi;
+	}
+
 	void allPOIsDone() {
 
 		sortCities();
@@ -220,7 +301,7 @@ public class PlacesFile {
 
 		int ofs = 0;
 		for (POIRecord p : pois)
-			ofs += p.calcOffset(ofs, poiFlags, cities.size(), postalCodes.size());
+			ofs += p.calcOffset(ofs, poiFlags, cities.size(), postalCodes.size(), highways.size(), exitFacilities.size());
 	}
 
 	private class CitySort {
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java b/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java
index 90d3e5a..d59d476 100644
--- a/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java
+++ b/src/uk/me/parabola/imgfmt/app/lbl/PlacesHeader.java
@@ -28,23 +28,27 @@ import uk.me.parabola.imgfmt.app.ImgFileReader;
  * @author Steve Ratcliffe
  */
 public class PlacesHeader {
-	private static final char COUNTRY_REC_LEN = 3;
-	private static final char REGION_REC_LEN = 5;
-	private static final char CITY_REC_LEN = 5;
-	private static final char UNK1_REC_LEN = 4;
-	private static final char UNK2_REC_LEN = 4;
-	private static final char ZIP_REC_LEN = 3;
-	private static final char HIGHWAY_REC_LEN = 6;
-	private static final char EXIT_REC_LEN = 5;
-	private static final char HIGHWAYDATA_REC_LEN = 3;
+
+	static final char COUNTRY_REC_LEN = 3;
+	static final char REGION_REC_LEN = 5;
+	static final char CITY_REC_LEN = 5;
+	static final char POI_INDEX_REC_LEN = 4;
+	static final char POI_TYPE_INDEX_REC_LEN = 4;
+	static final char ZIP_REC_LEN = 3;
+	static final char HIGHWAY_REC_LEN = 6;
+	static final char EXIT_REC_LEN = 5;
+	static final char HIGHWAYDATA_REC_LEN = 3;
 
 	private final Section country = new Section(COUNTRY_REC_LEN);
 	private final Section region = new Section(country, REGION_REC_LEN);
 	private final Section city = new Section(region, CITY_REC_LEN);
-	private final Section unk1 = new Section(city, UNK1_REC_LEN);
-	private final Section poiProperties = new Section(unk1);
-	private final Section unk2 = new Section(poiProperties, UNK2_REC_LEN);
-	private final Section zip = new Section(unk2, ZIP_REC_LEN);
+	private final Section poiIndex = new Section(city, POI_INDEX_REC_LEN);
+	private final Section poiProperties = new Section(poiIndex);
+	private final Section poiTypeIndex = new Section(poiProperties, POI_TYPE_INDEX_REC_LEN);
+	private final Section zip = new Section(poiTypeIndex, ZIP_REC_LEN);
+	private final Section highway = new Section(zip, HIGHWAY_REC_LEN);
+	private final Section exitFacility = new Section(highway, EXIT_REC_LEN);
+	private final Section highwayData = new Section(exitFacility, HIGHWAYDATA_REC_LEN);
 	private byte POIGlobalFlags ;
 
 	void setPOIGlobalFlags(byte flags) {
@@ -71,9 +75,9 @@ public class PlacesHeader {
 		writer.putChar(city.getItemSize());
 		writer.putInt(0);
 
-		writer.putInt(unk1.getPosition());
-		writer.putInt(unk1.getSize());
-		writer.putChar(unk1.getItemSize());
+		writer.putInt(poiIndex.getPosition());
+		writer.putInt(poiIndex.getSize());
+		writer.putChar(poiIndex.getItemSize());
 		writer.putInt(0);
 
 		writer.putInt(poiProperties.getPosition());
@@ -83,9 +87,9 @@ public class PlacesHeader {
 		writer.putChar((char) 0);
 		writer.put((byte) 0);
 
-		writer.putInt(unk2.getPosition());
-		writer.putInt(unk2.getSize());
-		writer.putChar(unk2.getItemSize());
+		writer.putInt(poiTypeIndex.getPosition());
+		writer.putInt(poiTypeIndex.getSize());
+		writer.putChar(poiTypeIndex.getItemSize());
 		writer.putInt(0);
 
 		writer.putInt(zip.getPosition());
@@ -93,21 +97,19 @@ public class PlacesHeader {
 		writer.putChar(zip.getItemSize());
 		writer.putInt(0);
 
-		int lastPos = zip.getEndPos();
-
-		writer.putInt(lastPos);
-		writer.putInt(0);
-		writer.putChar(HIGHWAY_REC_LEN);
+		writer.putInt(highway.getPosition());
+		writer.putInt(highway.getSize());
+		writer.putChar(highway.getItemSize());
 		writer.putInt(0);
 
-		writer.putInt(lastPos);
-		writer.putInt(0);
-		writer.putChar(EXIT_REC_LEN);
+		writer.putInt(exitFacility.getPosition());
+		writer.putInt(exitFacility.getSize());
+		writer.putChar(exitFacility.getItemSize());
 		writer.putInt(0);
 
-		writer.putInt(lastPos);
-		writer.putInt(0);
-		writer.putChar(HIGHWAYDATA_REC_LEN);
+		writer.putInt(highwayData.getPosition());
+		writer.putInt(highwayData.getSize());
+		writer.putChar(highwayData.getItemSize());
 		writer.putInt(0);
 	}
 
@@ -132,7 +134,7 @@ public class PlacesHeader {
 
 	int getLastPos() {
 		// Beware this is not really valid until all is written.
-		return zip.getEndPos();
+		return highwayData.getEndPos();
 	}
 
 	void setLabelEnd(int pos) {
@@ -155,10 +157,30 @@ public class PlacesHeader {
 		poiProperties.setSize(pos - poiProperties.getPosition());
 	}
 
+	void endPOIIndex(int pos) {
+		poiIndex.setSize(pos - poiIndex.getPosition());
+	}
+
+	void endPOITypeIndex(int pos) {
+		poiTypeIndex.setSize(pos - poiTypeIndex.getPosition());
+	}
+
 	void endZip(int pos) {
 		zip.setSize(pos - zip.getPosition());
 	}
 
+	void endHighway(int pos) {
+		highway.setSize(pos - highway.getPosition());
+	}
+
+	void endExitFacility(int pos) {
+		exitFacility.setSize(pos - exitFacility.getPosition());
+	}
+
+	void endHighwayData(int pos) {
+		highwayData.setSize(pos - highwayData.getPosition());
+	}
+
 	public int getNumCities() {
 		return city.getNumItems();
 	}
diff --git a/src/uk/me/parabola/mkgmap/build/MapBuilder.java b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
index eccd783..96d8808 100644
--- a/src/uk/me/parabola/mkgmap/build/MapBuilder.java
+++ b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
@@ -26,10 +26,12 @@ import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.Label;
 import uk.me.parabola.imgfmt.app.lbl.City;
 import uk.me.parabola.imgfmt.app.lbl.Country;
+import uk.me.parabola.imgfmt.app.lbl.ExitFacility;
 import uk.me.parabola.imgfmt.app.lbl.LBLFile;
 import uk.me.parabola.imgfmt.app.lbl.POIRecord;
 import uk.me.parabola.imgfmt.app.lbl.Region;
 import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.lbl.Highway;
 import uk.me.parabola.imgfmt.app.map.Map;
 import uk.me.parabola.imgfmt.app.net.NETFile;
 import uk.me.parabola.imgfmt.app.net.NODFile;
@@ -56,10 +58,12 @@ import uk.me.parabola.mkgmap.filters.MapFilterChain;
 import uk.me.parabola.mkgmap.filters.PolygonSplitterFilter;
 import uk.me.parabola.mkgmap.filters.RemoveEmpty;
 import uk.me.parabola.mkgmap.filters.SmoothingFilter;
+import uk.me.parabola.mkgmap.general.Exit;
 import uk.me.parabola.mkgmap.general.LevelInfo;
 import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
 import uk.me.parabola.mkgmap.general.MapDataSource;
 import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapExitPoint;
 import uk.me.parabola.mkgmap.general.MapLine;
 import uk.me.parabola.mkgmap.general.MapPoint;
 import uk.me.parabola.mkgmap.general.MapRoad;
@@ -88,6 +92,9 @@ public class MapBuilder implements Configurable {
 	private boolean doRoads;
 
 	private final Locator locator = new Locator();
+
+	private final java.util.Map<String, Highway> highways = new HashMap<String, Highway>();
+
 	private Country country;
 	private Region  region;
 
@@ -99,6 +106,8 @@ public class MapBuilder implements Configurable {
 	private boolean	poiAddresses = true;
 	private int		poiDisplayFlags;
 
+	private int poisCount;
+
 	public MapBuilder() {
 		regionName = null;
 	}
@@ -251,8 +260,10 @@ public class MapBuilder implements Configurable {
 		boolean doAutofill;
 
 		for (MapPoint p : src.getPoints()) {
-
-			if(p.isCity() == false &&
+			if(p.isExit()) {
+			    processExit(map, (MapExitPoint)p);
+			}
+			else if(p.isCity() == false &&
 				 (p.isRoadNamePOI() || poiAddresses))
 			{		
 				if(locationAutofillLevel > 0 || p.isRoadNamePOI())
@@ -394,6 +405,58 @@ public class MapBuilder implements Configurable {
 
 	}
 
+	private void processExit(Map map, MapExitPoint mep) {
+		LBLFile lbl = map.getLblFile();
+		String ref = mep.getMotorwayRef();
+		if(ref != null) {
+			Highway hw = highways.get(ref);
+			if(hw == null)
+				hw = makeHighway(map, ref);
+			if(hw == null) {
+			    log.error("Can't create exit " + mep.getName() + " on unknown highway " + ref);
+			    return;
+			}
+			String exitName = mep.getName();
+			String exitTo = mep.getTo();
+			Exit exit = new Exit(hw);
+			String facilityDescription = mep.getFacilityDescription();
+			log.info("creating " + ref + " exit facility " + exitName + " to " + exitTo + " with facility " + facilityDescription);
+			if(facilityDescription != null) {
+				// description is TYPE,DIR,FACILITIES,LABEL
+				// (same as Polish Format)
+				String[] atts = facilityDescription.split(",");
+				int type = 0;
+				if(atts.length > 0)
+					type = Integer.decode(atts[0]);
+				char direction = ' ';
+				if(atts.length > 1) {
+					direction = atts[1].charAt(0);
+					if(direction == '\'' && atts[1].length() > 1)
+						direction = atts[1].charAt(1);
+				}
+				int facilities = 0x0;
+				if(atts.length > 2)
+					facilities = Integer.decode(atts[2]);
+				String description = "";
+				if(atts.length > 3)
+					description = atts[3];
+				boolean last = true; // FIXME - handle multiple facilities?
+				ExitFacility ef = lbl.createExitFacility(type, direction, facilities, description, last);
+
+				exit.addFacility(ef);
+			}
+			mep.setExit(exit);
+			POIRecord r = lbl.createExitPOI(exitName, exit);
+			if(exitTo != null) {
+				Label ed = lbl.newLabel(exitTo);
+				exit.setDescription(ed);
+			}
+			poimap.put(mep, r);
+			// FIXME - set bottom bits of
+			// type to reflect facilities available?
+		}
+	}
+
 	/**
 	 * Drive the map generation by steping through the levels, generating the
 	 * subdivisions for the level and filling in the map elements that should
@@ -516,6 +579,7 @@ public class MapBuilder implements Configurable {
 
 		div.startDivision();
 
+		poisCount = 0;
 		processPoints(map, div, points);
 		processLines(map, div, lines);
 		processShapes(map, div, shapes);
@@ -597,6 +661,7 @@ public class MapBuilder implements Configurable {
 	 * @param points The points to be added.
 	 */
 	private void processPoints(Map map, Subdivision div, List<MapPoint> points) {
+		LBLFile lbl = map.getLblFile();
 		div.startPoints();
 		int res = div.getResolution();
 
@@ -620,13 +685,14 @@ public class MapBuilder implements Configurable {
 			p.setLatitude(coord.getLatitude());
 			p.setLongitude(coord.getLongitude());
 
-			if (div.getZoom().getLevel() == 0) {
+			if (point.isExit() || div.getZoom().getLevel() == 0) {
 				POIRecord r = poimap.get(point);
 				if (r != null)
 					p.setPOIRecord(r);
 			}
 
 			map.addMapObject(p);
+			lbl.createPOIIndex(name, ++poisCount, div, point.getType());
 		}
 
 		if (haveIndPoints) {
@@ -650,9 +716,9 @@ public class MapBuilder implements Configurable {
 				p.setLongitude(coord.getLongitude());
 
 				if(div.getZoom().getLevel() == 0 && name != null) {
-					// retrieve the City created earlier for
-					// this point and store the point info
-					// in it
+					// retrieve the City created
+					// earlier for this point and
+					// store the point info in it
 					City c = cityMap.get(point);
 
 					if(pointIndex > 255) {
@@ -660,11 +726,11 @@ public class MapBuilder implements Configurable {
 					} else {
 						c.setPointIndex((byte)pointIndex);
 						c.setSubdivision(div);
+						++pointIndex;
 					}
 				}
 
 				map.addMapObject(p);
-				++pointIndex;
 			}
 		}
 	}
@@ -736,6 +802,26 @@ public class MapBuilder implements Configurable {
 		}
 	}
 
+	Highway makeHighway(Map map, String ref) {
+		if(region == null) {
+			log.error("Region must be defined to create highway record for " + ref);
+			return null;
+		}
+
+		Highway hw = highways.get(ref);
+		if(hw == null) {
+			LBLFile lblFile = map.getLblFile();
+			log.info("creating highway " + ref);
+			hw = lblFile.createHighway(region, ref);
+			highways.put(ref, hw);
+		}
+		else if(hw.getRegion() != region) {
+			log.error("Highway " + ref + " defined in multiple regions");
+		}
+
+		return hw;
+	}
+
 	/**
 	 * It is not possible to represent large maps at the 24 bit resolution.  This
 	 * gets the largest resolution that can still cover the whole area of the
@@ -773,7 +859,7 @@ public class MapBuilder implements Configurable {
 		}
 	}
 
-	private static class LineAddFilter extends BaseFilter implements MapFilter {
+	private class LineAddFilter extends BaseFilter implements MapFilter {
 		private final Subdivision div;
 		private final Map map;
 		private final boolean doRoads;
diff --git a/src/uk/me/parabola/mkgmap/general/Exit.java b/src/uk/me/parabola/mkgmap/general/Exit.java
new file mode 100644
index 0000000..a97110e
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/Exit.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Steve Ratcliffe
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *
+ * Author: Steve Ratcliffe
+ * Create date: Jan 1, 2008
+ */
+package uk.me.parabola.mkgmap.general;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.lbl.ExitFacility;
+import uk.me.parabola.imgfmt.app.lbl.Highway;
+import uk.me.parabola.imgfmt.app.Label;
+
+/**
+ * Represent a motorway exit
+ *
+ * @author Mark Burton
+ */
+public class Exit {
+
+	public final static String TAG_ROAD_REF = "exit:road_ref";
+	public final static String TAG_TO = "exit:to";
+	public final static String TAG_FACILITY = "exit:facility";
+
+	private final Highway highway;
+	private Label label;
+	private Label description;
+	private List<ExitFacility> facilities = new ArrayList<ExitFacility>();
+
+	public Exit(Highway highway) {
+		this.highway = highway;
+	}
+
+	public void setLabel(Label label) {
+		this.label = label;
+	}
+
+	public void setDescription(Label description) {
+		this.description = description;
+	}
+
+	public void addFacility(ExitFacility facility) {
+		facilities.add(facility);
+	}
+
+	public boolean getOvernightParking() {
+		return false;	// FIXME
+	}
+
+	public Highway getHighway() {
+		return highway;
+	}
+
+	public List<ExitFacility> getFacilities() {
+		return facilities;
+	}
+
+	public Label getDescription() {
+		return description;
+	}
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapExitPoint.java b/src/uk/me/parabola/mkgmap/general/MapExitPoint.java
new file mode 100644
index 0000000..1bbfa9b
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/general/MapExitPoint.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2006 Steve Ratcliffe
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ * Author: steve
+ * Date: 24-Dec-2006
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+import uk.me.parabola.mkgmap.general.Exit;
+
+/**
+ * A point on the map that represents a motorway exit.
+ *
+ * @author Mark Burton
+ */
+public class MapExitPoint extends MapPoint {
+	private final String motorwayRef;
+	private final String to;
+	private String facilityDescription;
+	private Exit exit;
+
+	public MapExitPoint(String motorwayRef, String to) {
+		this.motorwayRef = motorwayRef;
+		this.to = to;
+	}
+
+	public MapExitPoint(MapExitPoint p) {
+		super(p);
+		this.motorwayRef = p.motorwayRef;
+		this.to = p.to;
+	}
+
+	public MapExitPoint copy() {
+		return new MapExitPoint(this);
+	}
+
+	public boolean isExit() {
+		return true;
+	}
+
+	public String getMotorwayRef() {
+		return motorwayRef;
+	}
+
+	public String getTo() {
+		return to;
+	}
+
+	public void setFacilityDescription(String facilityDescription) {
+		this.facilityDescription = facilityDescription;
+	}
+
+	public String getFacilityDescription() {
+		return facilityDescription;
+	}
+
+	public void setExit(Exit exit) {
+		this.exit = exit;
+	}
+
+	public Exit getExit() {
+		return exit;
+	}
+}
diff --git a/src/uk/me/parabola/mkgmap/general/MapLine.java b/src/uk/me/parabola/mkgmap/general/MapLine.java
index 3da30e2..5146f83 100644
--- a/src/uk/me/parabola/mkgmap/general/MapLine.java
+++ b/src/uk/me/parabola/mkgmap/general/MapLine.java
@@ -37,6 +37,7 @@ public class MapLine extends MapElement {
 	private int minLong = Integer.MAX_VALUE;
 	private int maxLat = Integer.MIN_VALUE;
 	private int maxLong = Integer.MIN_VALUE;
+	private String ref;
 
 	public MapLine() {
 	}
@@ -82,6 +83,18 @@ public class MapLine extends MapElement {
 		return false;
 	}
 
+	public boolean isHighway() {
+		return false;
+	}
+
+	public String getRef() {
+		return ref;
+	}
+
+	public void setRef(String ref) {
+		this.ref = ref;
+	}
+
 	/**
 	 * Get the mid-point of the bounding box for this element.  This is as good
 	 * an indication of 'where the element is' as any.  Previously we just
diff --git a/src/uk/me/parabola/mkgmap/general/MapPoint.java b/src/uk/me/parabola/mkgmap/general/MapPoint.java
index bb6fa03..31e68c8 100644
--- a/src/uk/me/parabola/mkgmap/general/MapPoint.java
+++ b/src/uk/me/parabola/mkgmap/general/MapPoint.java
@@ -31,7 +31,7 @@ public class MapPoint extends MapElement {
 	public MapPoint() {
 	}
 
-	private MapPoint(MapPoint p) {
+	protected MapPoint(MapPoint p) {
 		super(p);
 		location = p.location;
 	}
@@ -74,4 +74,8 @@ public class MapPoint extends MapElement {
 	{
 		return type >= 0x0100 && type <= 0x1100;
 	}
+
+	public boolean isExit() {
+		return false;
+	}
 }
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index 92733c3..b13f439 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -29,10 +29,12 @@ import uk.me.parabola.imgfmt.app.CoordNode;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.general.AreaClipper;
 import uk.me.parabola.mkgmap.general.Clipper;
+import uk.me.parabola.mkgmap.general.Exit;
 import uk.me.parabola.mkgmap.general.LineAdder;
 import uk.me.parabola.mkgmap.general.LineClipper;
 import uk.me.parabola.mkgmap.general.MapCollector;
 import uk.me.parabola.mkgmap.general.MapElement;
+import uk.me.parabola.mkgmap.general.MapExitPoint;
 import uk.me.parabola.mkgmap.general.MapLine;
 import uk.me.parabola.mkgmap.general.MapPoint;
 import uk.me.parabola.mkgmap.general.MapRoad;
@@ -288,7 +290,29 @@ public class StyledConverter implements OsmConverter {
 		if (!clipper.contains(node.getLocation()))
 			return;
 
-		MapPoint mp = new MapPoint();
+		// to handle exit points we use a subclass of MapPoint
+		// to carry some extra info (a reference to the
+		// motorway associated with the exit)
+		MapPoint mp;
+		int type = gt.getType();
+		if(type >= 0x2000 && type < 0x2800) {
+			String ref = node.getTag(Exit.TAG_ROAD_REF);
+			if(ref != null) {
+				String to = node.getTag(Exit.TAG_TO);
+				MapExitPoint mep = new MapExitPoint(ref, to);
+				String fd = node.getTag(Exit.TAG_FACILITY);
+				if(fd != null)
+					mep.setFacilityDescription(fd);
+				mp = mep;
+			}
+			else {
+				mp = new MapPoint();
+				log.error("Motorway exit " + node.getName() + " has no motorway! (either make the exit share a node with the motorway or specify the motorway ref with a " + Exit.TAG_ROAD_REF + " tag)");
+			}
+		}
+		else {
+			mp = new MapPoint();
+		}
 		elementSetup(mp, gt, node);
 		mp.setLocation(node.getLocation());
 
@@ -572,6 +596,14 @@ public class StyledConverter implements OsmConverter {
 		if(way.isBoolTag("toll"))
 			road.setToll();
 
+		// if the way is a motorway and has a ref tag, we may
+		// be generating a Garmin "highway" record for it so
+		// save the ref tag for later
+		String ref = way.getTag("ref");
+		if(ref != null) {
+			road.setRef(ref);
+		}
+
 		Way origWay = originalWay.get(way);
 		if(origWay == null)
 		    origWay = way;
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
index 059f85b..c3370a8 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
@@ -16,13 +16,16 @@
  */
 package uk.me.parabola.mkgmap.reader.osm.xml;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 
 import uk.me.parabola.imgfmt.app.Area;
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.Exit;
 import uk.me.parabola.mkgmap.general.MapDetails;
 import uk.me.parabola.mkgmap.general.RoadNetwork;
 import uk.me.parabola.mkgmap.reader.osm.Element;
@@ -56,6 +59,8 @@ class Osm5XmlHandler extends DefaultHandler {
 	private Map<Long, Way> wayMap;
 	private Map<Long, Relation> relationMap;
 	private final Map<String, Long> fakeIdMap = new HashMap<String, Long>();
+	private final List<Node> exits = new ArrayList<Node>();
+	private final List<Way> motorways = new ArrayList<Way>();
 
 	private static final int MODE_NODE = 1;
 	private static final int MODE_WAY = 2;
@@ -209,6 +214,13 @@ class Osm5XmlHandler extends DefaultHandler {
 					currentNode = new Node(currentElementId, co);
 					nodeMap.put(currentElementId, currentNode);
 				}
+
+				if((val.equals("motorway_junction") ||
+				    val.equals("services")) &&
+				   key.equals("highway")) {
+					exits.add(currentNode);
+				}
+
 				currentNode.addTag(key, val);
 			}
 		}
@@ -239,9 +251,9 @@ class Osm5XmlHandler extends DefaultHandler {
 		} else if (mode == MODE_WAY) {
 			if (qName.equals("way")) {
 				mode = 0;
-				if(routing &&
-				   (currentWay.getTag("highway") != null ||
-				    "ferry".equals(currentWay.getTag("route")))) {
+				String highway = currentWay.getTag("highway");
+				if(routing && (highway != null ||
+					       "ferry".equals(currentWay.getTag("route")))) {
 					// the way is a highway (or
 				    	// ferry route), so for each
 				    	// of it's points, increment
@@ -262,6 +274,9 @@ class Osm5XmlHandler extends DefaultHandler {
 						}
 					}
 				}
+				if("motorway".equals(highway) ||
+				   "trunk".equals(highway))
+					motorways.add(currentWay);
 				currentWay = null;
 				// ways are processed at the end of the document,
 				// may be changed by a Relation class
@@ -321,6 +336,26 @@ class Osm5XmlHandler extends DefaultHandler {
 	 * another exception.
 	 */
 	public void endDocument() throws SAXException {
+
+		for (Node e : exits) {
+			String refTag = Exit.TAG_ROAD_REF;
+			if(e.getTag(refTag) == null) {
+				for (Way w : motorways) {
+					String ref = w.getTag("ref");
+					if (w.getPoints().contains(e.getLocation())) {
+						if(ref != null) {
+							log.info("Adding " + refTag + "=" + ref + " to exit" + e.getTag("ref"));
+							e.addTag(refTag, ref);
+						}
+						else {
+							log.error("Motorway exit is positioned on a motorway that doesn't have a 'ref' tag");
+						}
+						break;
+					}
+				}
+			}
+		}
+
 		coordMap = null;
 		for (Relation r : relationMap.values())
 			converter.convertRelation(r);
