Hi

Sorry, the complete europe map still seems to trigger some limits.

It's again the mdr.img being>240MB. I uploaded the faulty file to the
mkgmap website. Here is the debug output ...

OK, thanks for that.

One more thought: the limit of 240 MB looks like the least siginifcant 4
bits of some limiting variable are masked out somehow,
256 - 16 = 240!?

Interesting...

Another thoght: Before r1919 the Europe map was working for me. What did
change with r1919 or later?

I started using the formula in:

  http://en.wikipedia.org/wiki/Logical_Block_Addressing#CHS_conversion

instead of just guessing how it works.

Also there were attempts to increase the max size, followed by setting
the max size based on the actual size.  Most of these changes have
mostly worked, but not for someone.

Is there a tool for download to analyse the imgfmt-structure?

For the disk header I use: http://sourceforge.net/projects/garmin-img/
The header is the first thing written so there is no need to let it
run to completion on a large file, nor worry if it crashes after
writing the *DSKIMG* file out. I use a patched version (patch attached against 1.1).

For almost everything else there is a program in http://svn.mkgmap.org.uk/display/trunk/ that will print the sections.

..Steve
Index: decode_header.cc
===================================================================
--- decode_header.cc	(revision 2)
+++ decode_header.cc	(working copy)
@@ -12,7 +12,8 @@
 	byte_t byte;
 	string str;
 	time_t ts;
-	udword_t subfile_offset;
+	udword_t subfile_offset= 0xffffffff;
+	byte_t dir_start;
 	
 	dec->set_outfile("DSKIMG", "header");
 	dec->print("XOR byte 0x%02x", img->xorbyte);
@@ -32,15 +33,15 @@
 	dec->print("%u sectors?", img->get_uword());
 	dec->print("%u heads?", img->get_uword());
 
+	dec->print("%u cyls", img->get_uword());
 	dec->print("???", img->get_word());
-	dec->print("???", img->get_word());
 
 	dec->print("%s", img->get_string(25).c_str());
 
 	ts= img->get_date();
 	dec->print("Created %24.24s", ctime(&ts));
 
-	dec->print("???", img->get_byte());
+	dec->print("Dir start?", (dir_start = img->get_byte()));
 
 	dec->print("%s", img->get_string(7).c_str());
 
@@ -72,8 +73,10 @@
 	dec->print("%u start-cylinder?", img->get_byte());
 	dec->print("%u system-type?", img->get_byte());
 	dec->print("%u end-head?", img->get_byte());
-	dec->print("%u end-sector?", img->get_byte());
-	dec->print("%u end-cylinder?", img->get_byte());
+	int s = img->get_byte() & 0xff;
+	dec->print("%u end-sector?", s & 0x3f);
+	int c = img->get_byte() & 0xff;
+	dec->print("%u end-cylinder?", ((s << 2) & 0x300) + c);
 	dec->print("%u rel-sectors?", img->get_udword());
 	dec->print("%u num-sectors?", img->get_udword());
 	dec->print(NULL, img->get_string(48).c_str());
@@ -82,26 +85,33 @@
 
 	dec->rawprint("*\n");
 
-	img->seek(0x400);
+	img->seek(dir_start * 0x200);
 
-	dec->print("???", img->get_byte());
-	dec->print("???", img->get_string(11).c_str());
-	dec->print("First subfile offset: 0x%06lx", 
-		subfile_offset= img->get_udword());
-	dec->print("???", img->get_byte());
-	dec->print("", img->get_string(15).c_str());
+	byte= img->get_byte();
+	if ( ! byte) {
+		img->seek(0x1000);
+	} else {
+		dec->print("???", img->get_byte());
+		dec->print("???", img->get_string(11).c_str());
+		dec->print("First subfile offset: 0x%06lx", 
+			subfile_offset= img->get_udword());
+		dec->print("???", img->get_byte());
+		dec->print("", img->get_string(15).c_str());
 
-	dec->print("Sequence block start", img->get_uword());
-	dec->rawprint("*\n");
-	dec->print("Sequence block end (block %u)",
-		img->last_seq_block(0x600));
-	if ( img->tell() != 0x600 ) {
-		dec->print("Sequence block padding", img->get_uword());
+		dec->print("Sequence block start", img->get_uword());
 		dec->rawprint("*\n");
+
+		off_t end = (dir_start+1) * 0x200;	
+		dec->print("Sequence block end (block %u)",
+			img->last_seq_block(end));
+		if ( img->tell() != end ) {
+			dec->print("Sequence block padding", img->get_uword());
+			dec->rawprint("*\n");
+		}
+
+		img->seek(end);
 	}
 
-	img->seek(0x600);
-
 	dec->banner("Begin FAT");
 	while ( img->tell() < subfile_offset ) {
 		img_fat_block_t fblock;
@@ -146,6 +156,9 @@
 			img->seek(next_block);
 		}
 		fblock.offset= seq*img->block_size();
+
+		if ( ! fblock.offset ) valid= 0;
+
 		if ( ! part && valid ) {
 			class ImgFile *ifile;
 			class ImgSubfile *subfile;
@@ -154,6 +167,9 @@
 				fblock.offset);
 			img->fat.insert(make_pair(fblock.fullname, fblock));
 
+			if ( fblock.offset && fblock.offset < subfile_offset )
+				subfile_offset= fblock.offset;
+
 			ifile= img->file_find(fblock.filename);
 			if ( ifile == NULL ) {
 				ifile= new ImgFile(img, fblock.filename);
@@ -161,8 +177,8 @@
 					ifile));
 			}
 
-			ifile->subfile_add(fblock.extension, fblock.offset,
-				fblock.size);
+			(void) ifile->subfile_add(fblock.extension,
+				fblock.offset, fblock.size);
 		}
 		dec->rawprint("\n");
 	}
Index: decode_tre.cc
===================================================================
--- decode_tre.cc	(revision 2)
+++ decode_tre.cc	(working copy)
@@ -23,7 +23,7 @@
 {
 	udword_t length, offset;
 	uword_t rsize;
-	off_t soffset, eoffset;
+	off_t soffset, eoffset, hoffset;
 	class ImgLBL *lbl;
 
 	tre= tre_in;
@@ -32,9 +32,10 @@
 	ifile= tre->ifile;
 
 	soffset= tre->offset();
+	hoffset= tre->h_offset();
 //	lbl= (class ImgLBL *) ifile->subfile_find("LBL");
 
-	img->seek(soffset);
+	img->seek(hoffset);
 
 	dec->set_outfile("TRE", "header");
 	dec->banner("TRE: Header");
@@ -321,7 +322,9 @@
 				subdiv.next_level_idx= img->get_uword();
 				dec->print("Next level at subdiv %u",
 					subdiv.next_level_idx);
-				if ( next_level_at == scount )
+				if ( next_level_at == scount ||
+					next_level_at > subdiv.next_level_idx )
+
 					next_level_at= subdiv.next_level_idx;
 			} else {
 				subdiv.next_level_idx= 0;
@@ -357,19 +360,22 @@
 		dec->comment("%u subdivisions", tre->nsubdivisions);
 		dec->comment(NULL);
 
-		for (i= tre->nlevels-1; i>= 0; --i) {
+		int level_count = tre->nlevels-1;
+		for (i= 24; i >= 0 ; i--) {
 			map_level_t level;
 
-			recsz= ( i ) ? 16 : 14;
-			ifile->level_get(i, &level);
+			recsz= ( level_count ) ? 16 : 14;
+			if (ifile->level_get(i, &level) < 0)
+				continue;
 
+			level_count--; 
 			nsubdivisions= level.nsubdiv;
 
 			dec->comment("Map Level %u", i);
 			dec->comment(NULL);
 
 			for (n= 0; n< nsubdivisions; ++n) {
-				dec->comment("Subdivision %u", scount);
+				dec->comment("Subdivision %u/%u", scount, nsubdivisions);
 
 				if ( scount > 1 )
 					dec->comment("Rgn start 0x%06x",
@@ -441,8 +447,9 @@
 	if ( tre->locked ) {
 		dec->print("width %u (unshifted) units", width);
 	} else {
+		uword_t unshift_width = width;
 		width<<= shiftby;
-		dec->print("width  %10.5f", img->degrees(width));
+		dec->print("width  %10.5f (%u)", img->degrees(width), unshift_width);
 	}
 	if ( subdiv->last ) dec->comment("last subdiv in chain");
 
@@ -450,8 +457,9 @@
 	if ( tre->locked ) {
 		dec->print("height %u (unshifted) units", height);
 	} else {
+		uword_t unshift_height = height;
 		height<<= shiftby;
-		dec->print("height %10.5f", img->degrees(height));
+		dec->print("height %10.5f (%u)", img->degrees(height), unshift_height);
 	}
 
 	if ( ! tre->locked ) {
@@ -467,6 +475,8 @@
 	int nrecs= tre->polyline_info.length/tre->polyline_info.rsize;
 	int n;
 
+	if ( ! nrecs ) return;
+
 	img->seek(tre->polyline_info.offset);
 	dec->set_outfile("TRE", "polylines");
 	dec->banner("TRE: Polyline information");
@@ -481,7 +491,7 @@
 		dec->print("Type %u, %s", type,
 			img->elem_polyline_name(type).c_str());
 		dec->print("max level %u?", img->get_byte());
-		dec->print("???", img->get_byte());
+		//dec->print("???", img->get_byte());
 	}
 }
 
@@ -490,6 +500,8 @@
 	int nrecs= tre->polygon_info.length/tre->polygon_info.rsize;
 	int n;
 
+	if ( ! nrecs ) return;
+
 	img->seek(tre->polygon_info.offset);
 	dec->set_outfile("TRE", "polygons");
 	dec->banner("TRE: Polygon information");
@@ -504,7 +516,7 @@
 		dec->print("Type %u, %s", type,
 			img->elem_polygon_name(type).c_str());
 		dec->print("max level %u?", img->get_byte());
-		dec->print("???", img->get_byte());
+		//dec->print("???", img->get_byte());
 	}
 }
 
@@ -513,6 +525,8 @@
 	int nrecs= tre->point_info.length/tre->point_info.rsize;
 	int n;
 
+	if ( ! nrecs ) return;
+
 	img->seek(tre->point_info.offset);
 	dec->set_outfile("TRE", "points");
 	dec->banner("TRE: Point information");
@@ -536,6 +550,8 @@
 	int nrecs= tre->copyright_info.length/tre->copyright_info.rsize;
 	int n;
 
+	if ( ! nrecs ) return;
+
 	img->seek(tre->copyright_info.offset);
 	dec->set_outfile("TRE", "copyright");
 	dec->banner("TRE: Copyrights");
@@ -564,3 +580,4 @@
 
 	dec->print("???", img->get_string(tre->unknown2_info.length).c_str());
 }
+
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 2)
+++ Makefile.in	(working copy)
@@ -2,8 +2,8 @@
 CXX=@CXX@
 CFLAGS=-g
 OBJS=main.o garminimg.o imgfile.o subfile.o tre.o lbl.o rgn.o net.o nod.o \
-	decoder.o decode_header.o decode_tre.o decode_lbl.o decode_rgn.o \
-	decode_net.o decode_nod.o
+	gmp.o decoder.o decode_header.o decode_tre.o decode_lbl.o \
+	decode_rgn.o decode_net.o decode_nod.o decode_gmp.o
 
 .SUFFIXES: .cc .o
 
Index: decoder.h
===================================================================
--- decoder.h	(revision 2)
+++ decoder.h	(working copy)
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <stdio.h>
 #include <string>
+#include <stdarg.h>
 
 using namespace std;
 
Index: lbl.cc
===================================================================
--- lbl.cc	(revision 2)
+++ lbl.cc	(working copy)
@@ -1,5 +1,7 @@
 #include <sys/types.h>
 #include <string>
+#include <stdio.h>
+#include <memory.h>
 #include "imgtypes.h"
 #include "garminimg.h"
 #include "lbl.h"
@@ -11,7 +13,9 @@
 	encoding6_spec= "`abcdefghijklmnopqrstuvwxyz~~~~~0123456789~~~~~~";
 
 	ifile= ifilein;
-	imgfile_offset= offset;
+	header_offset= imgfile_offset= offset;
+
+	memset(&poi_mask, 0, sizeof(poi_mask));
 }
 
 ImgLBL::~ImgLBL ()
@@ -19,6 +23,20 @@
 }
 
 //-------------------------------------------------------------------
+// POI properties 
+//-------------------------------------------------------------------
+
+byte_t ImgLBL::global_poi_flags ()
+{
+	return poi_flags;
+}
+
+byte_t ImgLBL::global_poi_flags (byte_t flags_in)
+{
+	return poi_flags= flags_in;
+}
+
+//-------------------------------------------------------------------
 // Label methods
 //-------------------------------------------------------------------
 
@@ -32,8 +50,13 @@
 	switch (encoding) {
 	case LBL_ENC_6BIT:
 		return label_parse_6bit (offset);
-		break;
+	case LBL_ENC_8BIT:
+		return label_parse_8bit(offset);
+	case LBL_ENC_10BIT:
+		return label_parse_8bit(offset);
 	}
+
+	return "(can't decode)";
 }
 
 //-------------------------------------------------------------------
@@ -132,6 +155,45 @@
 }
 
 //-------------------------------------------------------------------
+// 8-bit decoding methods
+//-------------------------------------------------------------------
+
+string ImgLBL::label_parse_8bit (off_t offset)
+{
+	bool lcont= false;
+	//int chset= SET_8_NORMAL;
+	unsigned char enc[3], data[4];
+	string label;
+
+	if ( offset > label_info.offset+label_info.length || 
+		offset < label_info.offset ) {
+
+		return "(invalid offset)";
+	}
+
+	if ( img->tell() != offset ) img->seek(offset);
+
+	for (;;) {
+		img->get_cstring(enc, 1);
+
+		if ( lcont ) img->sbuffer_append();
+		else img->sbuffer_set();
+
+		data[0]= enc[0];
+
+		if ( data[0] == 0 ) {
+			//img->sbuffer_rtrim(2);
+			//img->seek(-2, SEEK_CUR);
+			return label;
+		}
+
+		label.append((char*)data, 1);
+
+		lcont= true;
+	}
+}
+
+//-------------------------------------------------------------------
 // Locality methods
 //-------------------------------------------------------------------
 
Index: README
===================================================================
--- README	(revision 2)
+++ README	(working copy)
@@ -6,7 +6,17 @@
 About imgdecode
 ---------------
 
-This program is designed to aid in the decoding of Garmin IMG files.
+NOTE: This code has been designed to work on topo and road maps
+only.  No effort has been made towards parsing marine or aviation
+maps. 
+
+"NT" style maps do not decode past a few headers as this map file
+format is only partially understood.  City Navigator v8 files do
+not decode correctly, either, due to unknown changes in their data
+structures.  It is known to work correctly on City Navigator v7 and
+older map files, US TOPO files, and Metroguide maps (v7 and older).
+
+The program is designed to aid in the decoding of Garmin IMG files.
 It hexdumps the IMG file side-by-side with plain-text descriptions
 of what the particular bytes in the file represent.  Unknown
 data blocks are either unlabeled or labeled with a ???.  Files are
@@ -66,14 +76,5 @@
 What isn't working
 ------------------
 
-NOD section "unknown2" is not correct.  There are offsets into this
-file from NET and I know where they are, but don't understand the
-algorithm for getting to them, so parsing NOD is pretty much impossible
-for now.
+Much of NOD is still unknown.
 
-Much of NET is still unknown.
-
-This still blows up on some IMG files and I'm not sure why.  If you
-are running against a CityNav or City Select NA product, I can look into
-it if you send me the file name (and product version).
-
Index: garminimg.cc
===================================================================
--- garminimg.cc	(revision 2)
+++ garminimg.cc	(working copy)
@@ -12,6 +12,7 @@
 #include <algorithm>
 #include "garminimg.h"
 #include "elemdata.h"
+#include <memory.h>
 
 using namespace std;
 
Index: decode_lbl.cc
===================================================================
--- decode_lbl.cc	(revision 2)
+++ decode_lbl.cc	(working copy)
@@ -3,13 +3,14 @@
 #include "decoder.h"
 #include "decode_img.h"
 
-void decode_lbl_labels (off_t end);
+void decode_lbl_labels ();
 void decode_lbl_country_def ();
 void decode_lbl_region_def ();
 void decode_lbl_city_def ();
 void decode_lbl_zip ();
 void decode_lbl_poiprop ();
 void decode_lbl_hwy_def ();
+void decode_lbl_exit_svc ();
 
 static class GarminImg *img;
 static class ImgFile *ifile;
@@ -21,8 +22,7 @@
 {
 	udword_t length;
 	uword_t rsize;
-	off_t offset;
-	off_t soffset;
+	off_t offset, soffset, hoffset;
 
 	lbl= lbl_in;
 	dec= dec_in;
@@ -30,13 +30,16 @@
 	ifile= lbl->ifile;
 
 	soffset= lbl->offset();
+	hoffset= lbl->h_offset();
 
-	img->seek(soffset);
+	img->seek(hoffset);
 	dec->set_outfile("LBL", "header");
 	dec->banner("LBL: Header");
 
 	decode_common_header(dec, lbl);
 
+	// LBL section 1
+
 	offset= img->get_udword()+soffset;
 	dec->print("Data offset 0x%06lx", offset);
 	dec->print("Data length %lu bytes", length= img->get_udword());
@@ -48,6 +51,8 @@
 	lbl->label_info.length= length;
 	lbl->label_info.offset= offset;
 
+	// LBL section 2
+
 	offset= img->get_udword()+soffset;
 	dec->print("Country definitions at 0x%06lx", offset);
 	dec->print("Country definition length %lu bytes", 
@@ -60,6 +65,8 @@
 
 	dec->print("", img->get_udword());
 
+	// LBL section 3
+
 	offset= img->get_udword()+soffset;
 	dec->print("Region definitions at 0x%06lx", offset);
 	dec->print("Region definition length %lu bytes", 
@@ -72,6 +79,8 @@
 
 	dec->print("", img->get_udword());
 
+	// LBL section 4
+
 	offset= img->get_udword()+soffset;
 	dec->print("City definitions at 0x%06lx", offset);
 	dec->print("City definition length %lu bytes",
@@ -84,56 +93,91 @@
 
 	dec->print("", img->get_udword());
 
+	// LBL section 5
+
 	offset= img->get_udword()+soffset;
 	dec->print("Unknown1 section at 0x%06lx", offset);
 	dec->print("Unknown1 section length %lu bytes",
 		length= img->get_udword());
 	dec->print("Unknown1 record size %u bytes", rsize= img->get_uword());
 	if (length) ifile->offset_add(offset, LBL_UNKN1);
-	lbl->unkn1_info.length= length;
-	lbl->unkn1_info.offset= offset;
-	lbl->unkn1_info.offset= rsize;
 
 	dec->print("", img->get_udword());
 
+	// LBL section 6
+
 	offset= img->get_udword()+soffset;
 	dec->print("POI properties at 0x%06lx", offset);
 	dec->print("POI properties length %lu bytes",
 		length= img->get_udword());
-	dec->print("Zip bit is phone if no phone bit: %c", (lbl->zipisphone= img->get_byte()) ?
-		'Y' : 'N');
-	lbl->poiflags= img->get_byte();
-	if ( lbl->poiflags ) {
+	dec->print("???", img->get_byte());
+	lbl->global_poi_flags(img->get_byte());
+	if ( lbl->global_poi_flags() ) {
 		string s_flags;
 		bool has_street, has_street_num, has_city,
-			has_zip, has_phone, has_extra, has_u1, has_u2;
+			has_zip, has_phone, has_hwyexit, has_tides,
+			has_unkn;
+		char mask= 0x1;
 
-		has_street_num=	lbl->poiflags & 0x1;
-		has_street=	lbl->poiflags & 0x2;
-		has_city=	lbl->poiflags & 0x4;
-		has_zip=	lbl->poiflags & 0x8;
-		has_phone=	lbl->poiflags & 0x10;
-		has_extra=	lbl->poiflags & 0x20;
-		has_u1=		lbl->poiflags & 0x40;
-		has_u2=		lbl->poiflags & 0x80;
+		has_street_num=	lbl->global_poi_flags() & 0x1;
+		has_street=	lbl->global_poi_flags() & 0x2;
+		has_city=	lbl->global_poi_flags() & 0x4;
+		has_zip=	lbl->global_poi_flags() & 0x8;
+		has_phone=	lbl->global_poi_flags() & 0x10;
+		has_hwyexit=	lbl->global_poi_flags() & 0x20;
+		has_tides=	lbl->global_poi_flags() & 0x40;
+		has_unkn=	lbl->global_poi_flags() & 0x80;
 
-		if ( lbl->zipisphone && has_zip && ! has_phone ) {
-			has_zip= 0;
-			has_phone= 1;
+		if ( has_street_num ) {
+			s_flags+= "street_num,";
+			lbl->poi_mask.street_num= mask;
+			mask*= 2;
 		}
 
-		if ( has_street_num ) s_flags+= "street_num,";
-		if ( has_street ) s_flags+= "street,";
-		if ( has_city ) s_flags+= "city,";
-		if ( has_zip ) s_flags+= "zip,";
-		if ( has_phone ) s_flags+= "phone,";
-		if ( has_extra ) s_flags+= "xtra,";
-		if ( has_u1 ) s_flags+= "unkn1,";
-		if ( has_u2 ) s_flags+= "unkn2,";
+		if ( has_street ) {
+			s_flags+= "street,";
+			lbl->poi_mask.street= mask;
+			mask*= 2;
+		}
 
+		if ( has_city ) {
+			s_flags+= "city,";
+			lbl->poi_mask.city= mask;
+			mask*= 2;
+		}
+
+		if ( has_zip ) {
+			s_flags+= "zip,";
+			lbl->poi_mask.zip= mask;
+			mask*= 2;
+		}
+
+		if ( has_phone ) {
+			s_flags+= "phone,";
+			lbl->poi_mask.phone= mask;
+			mask*= 2;
+		}
+
+		if ( has_hwyexit ) {
+			s_flags+= "exit,";
+			lbl->poi_mask.hwyexit= mask;
+			mask*= 2;
+		}
+
+		if ( has_tides ) {
+			s_flags+= "tides,";
+			lbl->poi_mask.tides= mask;
+			mask*= 2;
+		}
+
+		if ( has_unkn ) {
+			s_flags+= "unkn,";
+		}
+
 		s_flags.erase(s_flags.size()-1);
-		dec->print("%s POIs: %s", img->base(lbl->poiflags,
-			2, 8).c_str(), s_flags.c_str());
+		dec->print("%s POIs: %s",
+			img->base(lbl->global_poi_flags(), 2, 8).c_str(),
+			s_flags.c_str());
 	} else dec->print("No global POI properties");
 	if (length) ifile->offset_add(offset, LBL_POI_PROP);
 	lbl->poiprop_info.length= length;
@@ -142,6 +186,8 @@
 	dec->print("", img->get_uword());
 	dec->print("", img->get_byte());
 
+	// LBL section 7
+
 	offset= img->get_udword()+soffset;
 	dec->print("Unknown2 section at 0x%06lx", offset);
 	dec->print("Unknown2 section length %lu bytes",
@@ -151,6 +197,8 @@
 
 	dec->print("", img->get_udword());
 
+	// LBL section 8
+
 	offset= img->get_udword()+soffset;
 	dec->print("Zip definitions at 0x%06lx", offset);
 	dec->print("Zip definition length %lu bytes",
@@ -163,6 +211,8 @@
 
 	dec->print("", img->get_udword());
 
+	// LBL section 9
+
 	offset= img->get_udword()+soffset;
 	dec->print("Highway definitions at 0x%06lx", offset);
 	dec->print("Highway definition length %lu bytes",
@@ -175,36 +225,52 @@
 
 	dec->print("", img->get_udword());
 
+	// LBL section 10
+
 	offset= img->get_udword()+soffset;
-	dec->print("Exit definitions at 0x%06lx", offset);
-	dec->print("Exit definition length %lu bytes",
+	dec->print("Exit services at 0x%06lx", offset);
+	dec->print("Exit services length %lu bytes",
 		length= img->get_udword());
-	dec->print("Exit record size %u bytes", rsize= img->get_uword());
-	if (length) ifile->offset_add(offset, LBL_EXIT_DEF);
+	dec->print("Exit services record size %u bytes",
+		rsize= img->get_uword());
+	if (length) ifile->offset_add(offset, LBL_EXIT_SVC);
+	lbl->exitsvc_info.length= length;
+	lbl->exitsvc_info.offset= offset;
+	lbl->exitsvc_info.rsize= rsize;
 
 	dec->print("", img->get_udword());
 
+	// LBL section 11
+
 	offset= img->get_udword()+soffset;
-	dec->print("Highway data definitions at 0x%06lx", offset);
-	dec->print("Highway data definition length %lu bytes",
+	dec->print("Exit list at 0x%06lx", offset);
+	dec->print("Exit list length %lu bytes",
 		length= img->get_udword());
-	dec->print("Highway data record size %u bytes",
+	dec->print("Exit list record size %u bytes",
 		rsize= img->get_uword());
-	if (length) ifile->offset_add(offset, LBL_HWY_DATA);
+	if (length) ifile->offset_add(offset, LBL_EXIT_LST);
+	lbl->exitlist_info.length= length;
+	lbl->exitlist_info.offset= offset;
+	lbl->exitlist_info.rsize= rsize;
 
-	dec->print("", img->get_udword());
+	// LBL section 12?
 
-	dec->print("Code page?", img->get_uword());
-
 	dec->print("???", img->get_udword());
+	dec->print("???", img->get_uword());
+	dec->print("???", img->get_udword());
 
+	// LBL section 13
+
 	offset= img->get_udword()+soffset;
 	dec->print("Sort descriptor at 0x%06lx", offset);
 	dec->print("Sort descriptor length %lu bytes", 
 		length= img->get_udword());
 	if (length) ifile->offset_add(offset, LBL_SORT_DESC);
-	lbl->sortlen= length;
+	lbl->sort_info.length= length;
+	lbl->sort_info.offset= offset;
 
+	// LBL section 14
+
 	offset= img->get_udword()+soffset;
 	dec->print("Unknown3 section at 0x%06lx", offset);
 	dec->print("Unknown3 section length %lu bytes",
@@ -214,6 +280,8 @@
 
 	dec->print("", img->get_uword());
 
+	// LBL section 15
+
 	offset= img->get_udword()+soffset;
 	dec->print("Unknown4 section at 0x%06lx", offset);
 	dec->print("Unknown4 section length %lu bytes",
@@ -238,104 +306,56 @@
 	off_t noffset;
 	unsigned int type;
 
-	// Parse the data segments in offset order.
+	// Parse the data segments in a sensible order.  Labels
+	// come first, followed by indexed sections (cities, zips,
+	// etc.)  POI properties go last, since they depend on all
+	// or many of the other fields.
 
-	img->seek(soffset);
-	type= ifile->offset_find(img->tell());
-	if ( type == 0 ) {
-		noffset= ifile->offset_next(img->tell());
-		if ( noffset > eoffset ) noffset= eoffset;
-		dec->print("???", img->get_string(noffset -
-			img->tell()).c_str());
-	}
+	decode_lbl_labels();
 
-	while ( img->tell() < eoffset ) {
-		type= ifile->offset_find(img->tell());
+	// Countries, regions, cities, zips in that order.
 
-		noffset= ifile->offset_next(img->tell());
+	decode_lbl_country_def();
 
-		switch (type) {
-		case LBL_LABELS:
-			dec->set_outfile("LBL", "labels");
-			dec->banner("LBL: Labels");
-			decode_lbl_labels(img->tell()+lbl->label_info.length);
-			break;
-		case LBL_COUNTRY_DEF:
-			dec->set_outfile("LBL", "countries");
-			dec->banner("LBL: Country definitions");
-			decode_lbl_country_def();
-			break;
-		case LBL_REGION_DEF:
-			dec->set_outfile("LBL", "regions");
-			dec->banner("LBL: Region definitions");
-			decode_lbl_region_def();
-			break;
-		case LBL_CITY_DEF:
-			dec->set_outfile("LBL", "cities");
-			dec->banner("LBL: City definitions");
-			decode_lbl_city_def();
-			break;
-		case LBL_UNKN1:
-			dec->set_outfile("LBL", "unknown1");
-			dec->banner("LBL: Unknown 1");
-			break;
-		case LBL_POI_PROP:
-			dec->set_outfile("LBL", "poi_properties");
-			dec->banner("LBL: POI Properties");
-			decode_lbl_poiprop();
-			break;
-		case LBL_UNKN2:
-			dec->set_outfile("LBL", "unknown2");
-			dec->banner("LBL: Unknown 2");
-			break;
-		case LBL_ZIP_DEF:
-			dec->set_outfile("LBL", "zipcodes");
-			dec->banner("LBL: Zip/Postal codes");
-			decode_lbl_zip();
-			break;
-		case LBL_HWY_DEF:
-			dec->set_outfile("LBL", "highways");
-			dec->banner("LBL: Highways");
-			decode_lbl_hwy_def();
-			break;
-		case LBL_EXIT_DEF:
-			dec->set_outfile("LBL", "exits");
-			dec->banner("LBL: Exit services");
-			break;
-		case LBL_HWY_DATA:
-			dec->set_outfile("LBL", "hwydata");
-			dec->banner("LBL: Highway data");
-			break;
-		case LBL_SORT_DESC:
-			dec->set_outfile("LBL", "sort");
-			dec->banner("LBL: Sort descriptor");
-			dec->print("%s", img->get_string(lbl->sortlen).c_str());
-			break;
-		case LBL_UNKN3:
-			dec->set_outfile("LBL", "unknown3");
-			dec->banner("LBL: Unknown 3");
-			break;
-		case LBL_UNKN4:
-			dec->set_outfile("LBL", "unknown4");
-			dec->banner("LBL: Unknown 4");
-			break;
-		}
+	decode_lbl_region_def();
 
-		if ( noffset > eoffset || noffset == 0 ) noffset= eoffset;
-		if ( img->tell() < noffset ) {
-			dec->print("???", img->get_string(noffset
-				- img->tell()).c_str());
+	decode_lbl_city_def();
 
-		}
-	}
+	decode_lbl_zip();
+
+	decode_lbl_hwy_def();
+
+	decode_lbl_exit_svc();
+
+	// POI properties depend on the above
+
+	decode_lbl_poiprop();
+
+	// The sort descriptor.  Just do it here.
+
+	img->seek(lbl->sort_info.offset);
+	dec->set_outfile("LBL", "sort");
+	dec->banner("LBL: Sort descriptor");
+	dec->print("%s", img->get_string(lbl->sort_info.length).c_str());
 }
 
-void decode_lbl_labels (off_t end)
+void decode_lbl_labels ()
 {
-	off_t offset;
+	off_t offset, end;
 	string label;
 
-	offset= img->tell();
+	offset= lbl->label_info.offset;
+	end= offset+lbl->label_info.length;
+	img->seek(offset);
+
+	dec->set_outfile("LBL", "labels");
+	dec->banner("LBL: Labels");
+
+	//if ( lbl->encoding != LBL_ENC_6BIT ) {
+	//	dec->rawprint("Encoding unknown\n");
+	//	return;
+	//}
+
 	while ( offset < end ) {
 		int n;
 		off_t lbloffset;
@@ -371,6 +391,11 @@
 	int nrecs= lbl->country_info.length / lbl->country_info.rsize;
 	int n;
 
+	img->seek(lbl->country_info.offset);
+
+	dec->set_outfile("LBL", "countries");
+	dec->banner("LBL: Country definitions");
+
 	for (n= 1; n<= nrecs; ++n) {
 		off_t loffset;
 		string country;
@@ -382,7 +407,6 @@
 		dec->comment("%s", country.c_str());
 //		img->country(n, &label);
 
-		++n;
 	}
 	dec->comment(NULL);
 }
@@ -393,6 +417,11 @@
 	int nrecs= lbl->region_info.length / lbl->region_info.rsize;
 	int n;
 
+	img->seek(lbl->region_info.offset);
+
+	dec->set_outfile("LBL", "regions");
+	dec->banner("LBL: Region definitions");
+
 	for (n= 1; n<= nrecs; ++n) {
 		uword_t cidx;
 		udword_t loffset;
@@ -416,6 +445,11 @@
 	int nrecs= lbl->city_info.length / lbl->city_info.rsize;
 	int n;
 
+	img->seek(lbl->city_info.offset);
+
+	dec->set_outfile("LBL", "cities");
+	dec->banner("LBL: City definitions");
+
 	for (n= 1; n<= nrecs; ++n) {
 		udword_t cdata;
 		uword_t cinfo, ridx;
@@ -431,9 +465,11 @@
 		ridx= (cinfo & 0x3FFF);
 		pref= (cinfo & 0x8000);
 		
-		if ( pref ) dec->print("City %u is IdxPoint %u in subdiv %u",
-			n, cdata>>16, cdata&0xFFFF);
-		else {
+		if ( pref ) {
+			dec->print("City %u is IdxPoint %u in subdiv %u",
+				n, cdata&0xff, (cdata>>8)&0xFFFF);
+			ifile->city_inc();
+		} else {
 			udword_t loffset= (udword_t) cdata;
 
 			dec->print("City %u label at 0x%06x", n, loffset);
@@ -454,6 +490,11 @@
 	int nrecs= lbl->zip_info.length / lbl->zip_info.rsize;
 	int n;
 
+	img->seek(lbl->zip_info.offset);
+
+	dec->set_outfile("LBL", "zipcodes");
+	dec->banner("LBL: Zip/Postal codes");
+
 	for (n= 1; n<= nrecs; ++n) {
 		udword_t offset= img->get_uint24();
 		string label;
@@ -466,15 +507,21 @@
 
 void decode_lbl_poiprop ()
 {
-	off_t soffset= img->tell();
-	off_t eos= img->tell() + lbl->poiprop_info.length;
-	udword_t poi_data, lbloffset;
+	off_t soffset= lbl->poiprop_info.offset;
+	off_t eos= soffset + lbl->poiprop_info.length;
+	udword_t poi_data, lbloffset, lblinfo;
 	bool override;
 
+	img->seek(soffset);
+
+	dec->set_outfile("LBL", "poi_properties");
+	dec->banner("LBL: POI Properties");
+
 	while ( img->tell() < eos ) {
 		byte_t flags;
 		bool has_street, has_street_num, has_city,
-			has_zip, has_phone, has_extra, has_u1, has_u2;
+			has_zip, has_phone, has_hwyexit, has_tides,
+			has_unkn;
 
 		poi_data= img->get_uint24();
 		lbloffset= (poi_data & 0x3FFFFF);
@@ -487,40 +534,40 @@
 			dec->print("%s override flags",
 				img->base(flags, 2, 8).c_str());
 
-		} else flags= lbl->poiflags;
+			has_street_num= flags & lbl->poi_mask.street_num;
+			has_street=	flags & lbl->poi_mask.street;
+			has_city=	flags & lbl->poi_mask.city;
+			has_zip=	flags & lbl->poi_mask.zip;
+			has_phone=	flags & lbl->poi_mask.phone;
+			has_hwyexit=	flags & lbl->poi_mask.hwyexit;
+			has_tides=	flags & lbl->poi_mask.tides;
 
-		has_street_num=	flags & 0x1;
-		has_street=	flags & 0x2;
-		has_city=	flags & 0x4;
-		has_zip=	flags & 0x8;
-		has_phone=	flags & 0x10;
-		has_extra=	flags & 0x20;
-		has_u1=		flags & 0x40;
-		has_u2=		flags & 0x80;
+		} else {
+			flags= lbl->global_poi_flags();
 
-/*
-		if ( lbl->zipisphone && has_zip && ! has_phone ) {
-			has_zip= 0;
-			has_phone= 1;
+			has_street_num=	flags & 0x1;
+			has_street=	flags & 0x2;
+			has_city=	flags & 0x4;
+			has_zip=	flags & 0x8;
+			has_phone=	flags & 0x10;
+			has_hwyexit=	flags & 0x20;
+			has_tides=	flags & 0x40;
+			has_unkn=	flags & 0x80;
 		}
-*/
 
-		if ( override ) {
-			string s_flags;
+		string s_flags;
 
-			if ( has_street_num ) s_flags+= "street_num,";
-			if ( has_street ) s_flags+= "street,";
-			if ( has_city ) s_flags+= "city,";
-			if ( has_zip ) s_flags+= "zip,";
-			if ( has_phone ) s_flags+= "phone,";
-			if ( has_extra ) s_flags+= "xtra,";
-			if ( has_u1 ) s_flags+= "unkn1,";
-			if ( has_u2 ) s_flags+= "unkn2,";
+		if ( has_street_num ) s_flags+= "street_num,";
+		if ( has_street ) s_flags+= "street,";
+		if ( has_city ) s_flags+= "city,";
+		if ( has_zip ) s_flags+= "zip,";
+		if ( has_phone ) s_flags+= "phone,";
+		if ( has_hwyexit ) s_flags+= "hwyexit,";
+		if ( has_tides ) s_flags+= "tides,";
 
-			if ( s_flags.size() )
-				s_flags.erase(s_flags.size()-1);
-			dec->print("Has %s", s_flags.c_str());
-		}
+		if ( s_flags.size() )
+			s_flags.erase(s_flags.size()-1);
+		dec->comment("Has %s", s_flags.c_str());
 
 		if ( has_street_num ) {
 			string snum= img->get_base11str('-');
@@ -571,13 +618,45 @@
 
 		if ( has_phone ) {
 			string phn= img->get_base11str('-');
-			if ( phn.size() )
-				dec->print("Ph num %s", phn.c_str());
+			if ( phn.empty() ) {
+				udword_t mpoffset;
+				string::size_type idx;
+
+				dec->print("phone num is label");
+				mpoffset= img->get_byte()<<16;
+				img->sbuffer_set();
+				mpoffset|= img->get_uword();
+				img->sbuffer_append();
+				img->sbuffer_recall();
+				dec->print("label at 0x%06x", mpoffset);
+				phn= ifile->label_get(mpoffset);
+				dec->comment("Phone %s", phn.c_str());
+			} else
+				dec->print("Phone num %s", phn.c_str());
 		}
 
-		if ( has_extra ) {
-			img->get_byte();
-			dec->print("xtra");
+		if ( has_hwyexit ) {
+			bool has_eidx, has_onpark;
+			string ehas;
+
+			lblinfo= img->get_uint24();
+			lbloffset= lblinfo & 0x3FFFF;
+			has_onpark= (lblinfo & 0x400000);
+			has_eidx= (lblinfo & 0x800000);
+
+			if ( has_onpark ) ehas+= " overnight-parking";
+			if ( has_eidx ) ehas+= " indexed";
+
+			dec->print("Exit label at 0x%06x", lbloffset);
+			dec->comment("%s", ifile->label_get(lbloffset).c_str());
+			if ( ehas.size() ) dec->comment("%s", ehas.c_str());
+			dec->print("Highway idx %u", img->get_byte());
+
+			if ( has_eidx ) 
+				dec->print("Exit svc idx %u",
+					( lbl->nexitsvcs > 255 ) ?
+					img->get_uword() :
+					img->get_byte() );
 		}
 
 		while ( (img->tell()-soffset) % lbl->omult &&
@@ -595,8 +674,151 @@
 	int nrecs= lbl->hwy_info.length / lbl->hwy_info.rsize;
 	int n;
 
+	img->seek(lbl->hwy_info.offset);
+
+	dec->set_outfile("LBL", "highways");
+	dec->banner("LBL: Highways");
+
+	lbl->nhwys= nrecs;
+
 	for (n= 1; n<= nrecs; ++n) {
-		dec->print("???", img->get_string(lbl->region_info.rsize).c_str());
+		udword_t loffset= img->get_uint24();
+		dec->print("Label at offset 0x%06x", loffset);
+		dec->comment("%s", ifile->label_get(loffset).c_str());
+		dec->print("Exit list at 0x%06x", img->get_uint24());
 	}
 }
 
+void decode_lbl_exit_svc ()
+{
+	int nrecs= lbl->exitsvc_info.length / lbl->exitsvc_info.rsize;
+	int n, c;
+
+	lbl->nexitsvcs= nrecs;
+
+	img->seek(lbl->exitsvc_info.offset);
+
+	dec->set_outfile("LBL", "exit_services");
+	dec->banner("LBL: Exit Services");
+
+	c= 1;
+	dec->comment("Exit 1");
+	dec->comment(NULL);
+	for (n= 1; n<= nrecs; ++n) {
+		udword_t loffset, lblinfo;
+		byte_t fac, dir, type, data;
+		string sdir, stype, sfac;
+
+		lblinfo= img->get_uint24();
+		loffset= lblinfo&0x3FFFFF;
+		if ( lblinfo & 0x800000 ) {
+			dec->comment("Exit %u", ++c);
+			dec->comment(NULL);
+		}
+
+		dec->print("Label at offset 0x%06x", loffset);
+		dec->comment("%s", ifile->label_get(loffset).c_str());
+
+		data= img->get_byte();
+		dir= (data&0xF0)>>4;
+		type= data&0xF;
+
+		switch (type) {
+		case 0x0:
+			stype= "diesel w/restaurant";
+			break;
+		case 0x1:
+			stype= "diesel w/clearance";
+			break;
+		case 0x2:
+			stype= "fuel";
+			break;
+		case 0x3:
+			stype= "restaurant";
+			break;
+		case 0x4:
+			stype= "lodging";
+			break;
+		case 0x5:
+			stype= "car service";
+			break;
+		case 0x6:
+			stype= "diesel service";
+			break;
+		case 0x7:
+			stype= "comm car wash";
+			break;
+		case 0x8:
+			stype= "campground";
+			break;
+		case 0x9:
+			stype= "medical";
+			break;
+		case 0xa:
+			stype= "ATM";
+			break;
+		case 0xb:
+			stype= "recreation";
+			break;
+		case 0xc:
+			stype= "attractions";
+			break;
+		case 0xd:
+			stype= "fast food";
+			break;
+		case 0xe:
+		case 0xf:
+			stype= "none";
+		}
+
+		switch (dir) {
+		case 0x0:
+		case 0x1:
+			sdir= "north";
+			break;
+		case 0x2:
+		case 0x3:
+			sdir= "south";
+			break;
+		case 0x4:
+		case 0x5:
+			sdir= "east";
+			break;
+		case 0x6:
+		case 0x7:
+			sdir= "west";
+			break;
+		case 0x8:
+		case 0x9:
+			sdir= "inner";
+			break;
+		case 0xa:
+		case 0xb:
+			sdir= "outer";
+			break;
+		case 0xc:
+		case 0xd:
+			sdir= "both";
+			break;
+		case 0xe:
+		case 0xf:
+			sdir= "none";
+		}
+
+		dec->print("%s / %s", sdir.c_str(), stype.c_str());
+
+		fac= img->get_byte();
+		if ( fac & 0x01 ) sfac+= "truck/RV parking,";
+		if ( fac & 0x02 ) sfac+= "conven store,";
+		if ( fac & 0x04 ) sfac+= "diesel fuel,";
+		if ( fac & 0x08 ) sfac+= "car wash,";
+		if ( fac & 0x10 ) sfac+= "liq propane,";
+		if ( fac & 0x20 ) sfac+= "truck scale,";
+		if ( fac & 0x40 ) sfac+= "open 24h,";
+
+		if ( sfac.length() ) sfac.erase(sfac.size()-1);
+
+		dec->print("Facilities: %s", sfac.c_str());
+		dec->comment(NULL);
+	}
+}
Index: garminimg.h
===================================================================
--- garminimg.h	(revision 2)
+++ garminimg.h	(working copy)
@@ -14,6 +14,8 @@
 class ImgSubfile;
 class ImgTRE;
 class ImgLBL;
+class ImgRGN;
+class ImgGMP;
 
 struct img_fat_block_struct {
 	string filename;
@@ -166,6 +168,7 @@
 	zip_cache_t zips;
 	levels_t levels;
 	subdivisions_t subdivisions;
+	int indexed_cities;
 
 public:
 	class GarminImg *img;
@@ -176,7 +179,8 @@
 
 	// Subfile methods
 
-	void subfile_add (string type, off_t offset, udword_t size);
+	class ImgSubfile *subfile_add (string type, off_t offset,
+		udword_t size);
 	class ImgSubfile *subfile_find (string type);
 	off_t subfile_offset (string type);
 
@@ -203,6 +207,7 @@
 	vector<string> region_get_ar (uword_t idx);
 
 	void city_add (uword_t idx, string name, uword_t ridx);
+	void city_inc (void);
 	string city_get (uword_t idx);
 	vector<string> city_get_ar (uword_t idx);
 	uword_t ncities ();
@@ -231,14 +236,19 @@
 };
 
 class ImgSubfile {
+	friend class ImgGMP;
 	friend class ImgTRE;
 	friend class ImgLBL;
 	friend class ImgRGN;
 	friend class ImgNET;
 	friend class ImgNOD;
 
-	off_t imgfile_offset;
+	off_t imgfile_offset;	 // Offset of the subfile
 
+	off_t header_offset;	// Offset of the header in the subfile
+				// This is imgfile_offset for "old" style
+				// IMG files but differs for "NT" style
+
 public:
 	class ImgFile *ifile;
 	class GarminImg *img;
@@ -251,7 +261,10 @@
 
 	// Offset methods
 
+	void set_header_offset (off_t offset_new);
+	void set_size (udword_t size_new);
 	off_t offset ();
+	off_t h_offset ();
 };
 
 // Subfile data structures
@@ -269,6 +282,14 @@
 
 // Subfile class defintions
 
+class ImgGMP : public ImgSubfile {
+public:
+	int omult;
+
+	ImgGMP (class ImgFile *ifilein, off_t offset);
+	~ImgGMP ();
+};
+
 class ImgNOD : public ImgSubfile {
 public:
 	struct sec_info_struct unknown1_info, unknown2_info, unknown3_info;
@@ -280,8 +301,8 @@
 
 class ImgNET : public ImgSubfile {
 public:
-	struct sec_info_struct roads_info, unknown1_info, unknown2_info;
-	int omult;
+	struct sec_info_struct roads_info, unknown1_info, sorted_info;
+	int omult1, omult2;
 
 	ImgNET (class ImgFile *ifilein, off_t offset);
 	~ImgNET ();
@@ -317,25 +338,43 @@
 #define LBL_ENC_6BIT	6
 #define LBL_ENC_8BIT	9	// Yes, that's correct
 #define LBL_ENC_10BIT	10
+#define LBL_ENC_NT	11
 
 class ImgLBL : public ImgSubfile {
 	const char *encoding6, *encoding6_shift, *encoding6_spec;
+	byte_t poi_flags;
 
 	// Private 6 bit label methods
 
 	string char_6bit (byte_t byte, int *chset);
 	string label_parse_6bit (off_t offset);
+	string label_parse_8bit (off_t offset);
 
 public:
 	struct sec_info_struct country_info, region_info, city_info,
-		poiprop_info, zip_info, unkn1_info, label_info,
-		hwy_info;
-	int omult, poiflags, ncities, nzips, encoding, sortlen;
-	bool zipisphone;
+		poiprop_info, zip_info, label_info, hwy_info,
+		sort_info, exitlist_info, exitsvc_info;
 
+	int omult, ncities, nzips, encoding, nhwys, nexitsvcs;
+
+	struct poi_mask_struct {
+		char street_num;
+		char street;
+		char city;
+		char zip;
+		char phone;
+		char hwyexit;
+		char tides;
+	} poi_mask;
+
 	ImgLBL (class ImgFile *ifilein, off_t offset);
 	~ImgLBL ();
 
+	// POI properties functions
+
+	byte_t global_poi_flags ();
+	byte_t global_poi_flags (byte_t flags_in);
+
 	// Locality functions
 
 	void country_def_parse (off_t offset);
@@ -369,8 +408,8 @@
 #define	LBL_UNKN2       0x1007
 #define	LBL_ZIP_DEF     0x1008
 #define	LBL_HWY_DEF     0x1009
-#define	LBL_EXIT_DEF    0x100A
-#define	LBL_HWY_DATA    0x100B
+#define	LBL_EXIT_SVC    0x100A
+#define	LBL_EXIT_LST    0x100B
 #define	LBL_SORT_DESC   0x100C
 #define	LBL_UNKN3       0x100D
 #define	LBL_UNKN4       0x100E
@@ -378,7 +417,7 @@
 #define NET_ROAD_DEF	0x2001
 #define NET_ROAD_REC	0x2002
 #define NET_UNKN1	0x2003
-#define NET_UNKN2	0x2004
+#define NET_SORTED	0x2004
 
 #define NOD_UNKN1	0x3001
 #define NOD_UNKN2	0x3002
Index: imgfile.cc
===================================================================
--- imgfile.cc	(revision 2)
+++ imgfile.cc	(working copy)
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include "garminimg.h"
 
 using namespace std;
@@ -20,12 +21,16 @@
 // Subfile methods
 //----------------------------------------------------------------------
 
-void ImgFile::subfile_add (string type, off_t offset, udword_t sz)
+class ImgSubfile *ImgFile::subfile_add (string type, off_t offset, udword_t sz)
 {
 	class ImgSubfile *subfile= NULL;
 
+	if ( ! offset ) return NULL;
+
 	if ( type == "TRE" ) {
 		subfile= new ImgTRE (this, offset);
+	} else if ( type == "GMP" ) {
+		subfile= new ImgGMP (this, offset);
 	} else if ( type == "LBL" ) {
 		subfile= new ImgLBL (this, offset);
 	} else if ( type == "RGN" ) {
@@ -36,18 +41,28 @@
 		subfile= new ImgNOD (this, offset);
 	} else {
 		fprintf(stderr, "Unknown subfile %s\n", type.c_str());
-		return;
+		return NULL;
 	}
 
 	subfile->size= sz;
 	subfile->img= img;
 	subfiles.insert(make_pair(type, subfile));
+
+	return subfile;
 }
 
 class ImgSubfile *ImgFile::subfile_find (string type)
 {
 	subfile_list_t::iterator sfpos= subfiles.find(type);
 
+/*
+	for (sfpos= subfiles.begin(); sfpos != subfiles.end();
+	++sfpos) {
+		printf(">> Type= %s (%08x)\n", sfpos->first.c_str(),
+			sfpos->second);
+	}
+*/
+
 	if ( sfpos == subfiles.end() ) return NULL;
 
 	return sfpos->second;
@@ -206,6 +221,11 @@
 	cities.insert(make_pair(idx, city));
 }
 
+void ImgFile::city_inc(void)
+{
+	ImgFile::indexed_cities++;
+}
+
 string ImgFile::city_get (uword_t idx)
 {
 	locality_cache_t::iterator cpos;
@@ -237,7 +257,7 @@
 
 uword_t ImgFile::ncities ()
 {
-	return cities.size();
+	return ImgFile::indexed_cities + cities.size();
 }
 
 void ImgFile::zip_add (uword_t idx, string zip)
Index: nod.cc
===================================================================
--- nod.cc	(revision 2)
+++ nod.cc	(working copy)
@@ -6,7 +6,7 @@
 ImgNOD::ImgNOD (class ImgFile *ifilein, off_t offset)
 {
 	ifile= ifilein;
-	imgfile_offset= offset;
+	header_offset= imgfile_offset= offset;
 }
 
 ImgNOD::~ImgNOD ()
Index: decode_img.h
===================================================================
--- decode_img.h	(revision 2)
+++ decode_img.h	(working copy)
@@ -7,6 +7,8 @@
 
 void decode_common_header (class Decoder *dec, class ImgSubfile *sub);
 
+void decode_gmp_header (class Decoder *dec, class ImgGMP *sub);
+
 void decode_tre_header (class Decoder *dec, class ImgTRE *sub);
 void decode_tre_body ();
 
Index: decode_nod.cc
===================================================================
--- decode_nod.cc	(revision 2)
+++ decode_nod.cc	(working copy)
@@ -16,7 +16,7 @@
 {
 	udword_t length, offset;
 	uword_t rsize;
-	off_t soffset, eoffset;
+	off_t soffset, eoffset, hoffset;
 
 	nod= nod_in;
 	dec= dec_in;
@@ -24,8 +24,9 @@
 	ifile= nod->ifile;
 
 	soffset= nod->offset();
+	hoffset= nod->h_offset();
 
-	img->seek(soffset);
+	img->seek(hoffset);
 
 	dec->set_outfile("NOD", "header");
 	dec->banner("NOD: Header");
@@ -83,8 +84,8 @@
 
 	img->seek(soffset);
 
-	dec->set_outfile("NOD", "unknown1");
-	dec->banner("NOD: Unknown section 1");
+	dec->set_outfile("NOD", "section1");
+	dec->banner("NOD: Section 1");
 
 	dec->print("???", img->get_string(eoffset-soffset).c_str());
 }
@@ -93,15 +94,30 @@
 {
 	off_t soffset= nod->unknown2_info.offset;
 	off_t eoffset= nod->unknown2_info.offset+nod->unknown2_info.length;
+	off_t noffset= eoffset;
 
+	return; // XXX sr fix up this routine
 	img->seek(soffset);
 
-	dec->set_outfile("NOD", "unknown2");
-	dec->banner("NOD: Unknown section 2");
+	dec->set_outfile("NOD", "section2");
+	dec->banner("NOD: Section 2");
 
 	while (img->tell() < eoffset) {
+		byte_t data, rclass, sclass;
+
+		noffset= ifile->offset_next(img->tell());
+		if ( noffset > eoffset || noffset == 0 ) noffset= eoffset;
+
 		dec->comment("Offset 0x%06x", img->tell()-soffset);
-		dec->print("???", img->get_string(7).c_str());
+		data= img->get_byte();
+		rclass= (data&0xF0)>>4;
+		sclass= data&0xF;
+		dec->print("Road class 0x%x", rclass);
+		dec->comment("Speed class 0x%x", sclass);
+		dec->print("NOD1 offset 0x%06x?", img->get_uint24());
+
+		dec->print("???", img->get_string(noffset-img->tell()).c_str());
+		dec->comment(NULL);
 	}
 }
 
@@ -113,13 +129,14 @@
 
 	img->seek(soffset);
 
-	dec->set_outfile("NOD", "unknown3");
-	dec->banner("NOD: Unknown section 3");
+	dec->set_outfile("NOD", "boundary_nodes");
+	dec->banner("NOD: Boundary nodes");
 
 	for (n= 1; n<= nrecs; ++n) {
 		dec->comment("Record %u", n);
-		dec->print("???",
-			img->get_string(nod->unknown3_info.rsize).c_str());
+		dec->print("%.6f E", img->degrees(img->get_int24()));
+		dec->print("%.6f N", img->degrees(img->get_int24()));
+		dec->print("???", img->get_uint24());
 		dec->comment(NULL);
 	}
 }
Index: main.cc
===================================================================
--- main.cc	(revision 2)
+++ main.cc	(working copy)
@@ -2,6 +2,7 @@
 #include "garminimg.h"
 #include "decoder.h"
 #include "decode_img.h"
+#include <stdlib.h>
 
 void usage ();
 
@@ -21,8 +22,12 @@
 
 	img->set_fileent();
 	while ( (ifile= img->get_fileent()) != NULL ) {
-		class ImgSubfile *sub= ifile->subfile_find("TRE");
+		class ImgSubfile *sub= NULL;
+		
+		sub= ifile->subfile_find("GMP");
+		if ( sub != NULL ) decode_gmp_header(&dec, (ImgGMP *) sub);
 
+		sub= ifile->subfile_find("TRE");
 		if ( sub != NULL ) {
 			class ImgTRE *tre= (ImgTRE *) sub;
 			class ImgLBL *lbl;
@@ -60,7 +65,7 @@
 			if ( net ) decode_net_body();
 			if ( nod ) decode_nod_body();
 		} else {
-			fprintf(stderr, "TRE not found in\n");
+			fprintf(stderr, "TRE not found\n");
 			return -1;
 		}
 	}
Index: net.cc
===================================================================
--- net.cc	(revision 2)
+++ net.cc	(working copy)
@@ -6,7 +6,7 @@
 ImgNET::ImgNET (class ImgFile *ifilein, off_t offset)
 {
 	ifile= ifilein;
-	imgfile_offset= offset;
+	header_offset= imgfile_offset= offset;
 }
 
 ImgNET::~ImgNET ()
Index: rgn.cc
===================================================================
--- rgn.cc	(revision 2)
+++ rgn.cc	(working copy)
@@ -3,7 +3,7 @@
 ImgRGN::ImgRGN (class ImgFile *ifilein, off_t offset)
 {
 	ifile= ifilein;
-	imgfile_offset= offset;
+	header_offset= imgfile_offset= offset;
 }
 
 ImgRGN::~ImgRGN ()
Index: decode_net.cc
===================================================================
--- decode_net.cc	(revision 2)
+++ decode_net.cc	(working copy)
@@ -1,4 +1,5 @@
 #include <math.h>
+#include <stdlib.h>
 #include "imgtypes.h"
 #include "garminimg.h"
 #include "decoder.h"
@@ -7,25 +8,28 @@
 static class GarminImg *img;
 static class ImgFile *ifile;
 static class ImgNET *net;
+static class ImgNOD *nod;
 static class Decoder *dec;
 
 void decode_net_roads ();
-void decode_net_unkn2 ();
+void decode_net_sorted ();
 
 void decode_net_header (class Decoder *dec_in, class ImgNET *net_in)
 {
 	udword_t length, offset;
 	uword_t rsize;
-	off_t soffset, eoffset;
+	off_t soffset, eoffset, hoffset;
 
 	net= net_in;
 	dec= dec_in;
 	img= dec->img;
 	ifile= net->ifile;
+	nod= (ImgNOD *) ifile->subfile_find("NOD");
 
 	soffset= net->offset();
+	hoffset= net->h_offset();
 
-	img->seek(soffset);
+	img->seek(hoffset);
 
 	dec->set_outfile("NET", "header");
 	dec->banner("NET: Header");
@@ -40,13 +44,15 @@
 	net->roads_info.length= length;
 
 	dec->print("Road record offsets are x%u",
-		net->omult= int(pow(2.0,img->get_byte())));
+		net->omult1= int(pow(2.0,img->get_byte())));
 
 	dec->print("Unknown1 at offset 0x%08x", 
 		offset= img->get_udword()+soffset);
 	dec->print("Unknown1 length %ld bytes",
 		length= img->get_udword());
-	dec->print(NULL, img->get_byte());
+	dec->print("Unknown1 offsets are x%u", 
+		net->omult2= int(pow(2.0,img->get_byte())));
+
 	ifile->offset_add(offset, NET_UNKN1);
 	net->unknown1_info.offset= offset;
 	net->unknown1_info.length= length;
@@ -58,9 +64,9 @@
 	dec->print("Unknown2 record size %u bytes", 
 		rsize= img->get_uword());
 	ifile->offset_add(offset, NET_UNKN1);
-	net->unknown2_info.offset= offset;
-	net->unknown2_info.length= length;
-	net->unknown2_info.rsize= rsize;
+	net->sorted_info.offset= offset;
+	net->sorted_info.length= length;
+	net->sorted_info.rsize= rsize;
 
 	dec->print("???", img->get_udword());
 	dec->print("???", img->get_byte());
@@ -74,13 +80,14 @@
 
 void decode_net_body ()
 {
+	// Sorted road list
+
+	decode_net_sorted ();
+
 	// Parse road information first.
 
 	decode_net_roads ();
 
-	// Unknow section 2.  I think these may be intersections.
-
-	decode_net_unkn2 ();
 }
 
 void decode_net_roads ()
@@ -98,12 +105,14 @@
 
 	while ( img->tell() < eoffset ) {
 		udword_t lbloffset, roadinfo;
-		byte_t data;
+		double roadlen;
+		byte_t data, flags;
 		bool repeat;
 		off_t noffset;
-		int i, n;
+		int i, n, lcount;
 		unsigned int otype;
-		string stream;
+		string stream, shas;
+		bool has_addr, has_nod, has_dir;
 
 		otype= ifile->offset_find(img->tell());
 		if ( otype != NET_ROAD_REC && otype != NET_ROAD_DEF ) {
@@ -115,36 +124,160 @@
 		dec->comment(NULL);
 		dec->comment("Road offset 0x%06x", img->tell()-soffset);
 
+		if ( img->tell() == soffset ) {
+			if ( img->get_byte() == 0x2f ) {
+				dec->print("NULL record?");
+			} else img->seek(-1, SEEK_CUR);
+		}
+
 		repeat= true;
 		while ( repeat ) {
+			bool net2ptr;
+
 			lbloffset= img->get_uint24();
 			repeat= !(lbloffset & 0x800000);
+			net2ptr= (lbloffset & 0x400000);
 			lbloffset&= 0x3FFFFF;
 			dec->print("Label 0x%06x: %s", lbloffset,
 				ifile->label_get(lbloffset).c_str());
+			if ( net2ptr ) {
+				udword_t n2offset= img->get_uint24();
+				dec->print("NET2 offset 0x%06x", n2offset);
+			}
 		}
 
-		data= img->get_byte();
-		dec->print("Road data/flags %s?",
-			img->base(data, 2, 8).c_str());
-		dec->print("???", img->get_byte());
-		dec->print("???", img->get_uword());
+		flags= img->get_byte();
+		dec->print("Road flags %s",
+			img->base(flags, 2, 8).c_str());
 
+		shas.clear();
+		has_dir= flags&0x02;
+		has_addr= flags&0x10;
+		has_nod= flags&0x40;
+
+		if ( has_addr ) shas+= " addr";
+		if ( has_nod ) shas+= " nod";
+		if ( has_dir ) shas+= " direction";
+
+		if ( shas.size() ) dec->comment("has%s", shas.c_str());
+
+		roadlen= ((double) img->get_uint24()) * 7.8369461;
+		if ( roadlen < 528 ) 
+			dec->print("Road len %d ft", (int) roadlen);
+		else
+			dec->print("Road len %.2f mi", roadlen/5280.0);
+
 		repeat= true;
-		n= 0;
+		n= lcount= 0;
 		while ( repeat ) {
+			int cnt;
+
 			data= img->get_byte();
 			repeat= !(data&0x80);
-			++n;
-			dec->print("unknown, for idx %d?", n);
+			cnt= (data&0x7F);
+			n+= cnt;
+			dec->print("%u indices in level %u", cnt, lcount);
+			++lcount;
 		}
 
 		for (i= 0; i< n; ++i) {
 			roadinfo= img->get_uint24();
-			dec->print("Index %u, subdiv %u?",
+			dec->print("Index %u, subdiv %u",
 				(roadinfo&0xFF), (roadinfo&0xFFFF00)>>8);
 		}
 
+		if ( has_addr ) {
+			string sfields= "Fields 1-3:";
+			int fields[4];
+
+			dec->print("%u address blocks", img->get_byte());
+			data= img->get_byte();
+
+			for (i= 1; i<= 3; ++i) {
+				byte_t mask= 0x3<<(i*2);
+				byte_t val= (data&mask)>>(i*2);
+
+				switch (val) {
+				case 0x0:
+					// number field
+					sfields+= " nmbr";
+					break;
+				case 0x1:
+					// unknown
+					sfields+= " ???";
+					break;
+				case 0x2:
+					// LBL field
+					sfields+= " lbl";
+					break;
+				case 0x3:
+					// empty
+					sfields+= " empty";
+					break;
+				}
+
+				fields[i]= val;
+			}
+
+			dec->print("%s", sfields.c_str());
+
+			for (i= 1; i<= 3; ++i) {
+				string label;
+				byte_t val;
+
+				switch (fields[i]) {
+				case 0x0:
+					dec->print("field %u: %d bytes", i,
+						val= img->get_byte());
+					dec->print("???",
+						img->get_string(val).c_str());
+					break;
+				case 0x1:
+					dec->print("???", img->get_byte());
+					break;
+				case 0x2:
+					switch (i) {
+					case 1:
+						val= ( ifile->ncities()>255 ) ?
+							img->get_uword() :
+							img->get_byte();
+						dec->print("Zip idx %u", val);
+						break;
+					case 2:
+						val= ( ifile->nzips()>255 ) ?
+							img->get_uword() :
+							img->get_byte();
+						dec->print("City idx %u", val);
+						break;
+					case 3:
+						dec->print("???",
+							img->get_byte());
+						break;
+					}
+					break;
+				}
+			}
+		}
+
+		if ( has_nod ) {
+			data= img->get_byte();
+			off_t nodoff;
+
+			if ( data & 0x1 ) {
+				dec->print("Two-byte NOD offset");
+				nodoff= img->get_uword();
+			} else if ( data & 0x3 ) {
+				dec->print("Three-byte NOD offset");
+				nodoff= img->get_uint24();
+			}
+
+			dec->print("NOD offset 0x%06x", nodoff);
+			ifile->offset_add(nodoff+nod->unknown2_info.offset,
+				NOD_UNKN2);
+		}
+
+		if ( ifile->offset_find(img->tell()) ) continue;
+
 		noffset= ifile->offset_next(img->tell());
 		if ( noffset > eoffset || noffset == 0 ) noffset= eoffset;
 
@@ -153,21 +286,31 @@
 	}
 }
 
-void decode_net_unkn2 ()
+void decode_net_sorted ()
 {
-	off_t soffset= net->unknown2_info.offset;
-	off_t eoffset= soffset+net->unknown2_info.length;
-	uword_t nrecs= net->unknown2_info.length/net->unknown2_info.rsize;
+	off_t soffset= net->sorted_info.offset;
+	off_t eoffset= soffset+net->sorted_info.length;
+	off_t rdoffset= net->roads_info.offset;
+	uword_t nrecs= net->sorted_info.length/net->sorted_info.rsize;
 	uword_t i;
 
-	img->seek(net->unknown2_info.offset);
-	dec->set_outfile("NET", "unknown2");
-	dec->banner("NET: Unknown Section 2 (Intersections?)");
+	img->seek(net->sorted_info.offset);
+	dec->set_outfile("NET", "sorted_roads");
+	dec->banner("NET: Sorted roads");
 
 	for (i= 1; i<= nrecs; ++i) {
+		udword_t lblinfo;
+		off_t offset;
+		int num;
+
 		dec->comment("Record %u", i);
 
-		dec->print("Offset 0x%06x ?", (img->get_uint24()&0x3FFFFF));
+		lblinfo= img->get_uint24();
+		offset= lblinfo&0x3FFFFF;
+		num=  ((lblinfo&0xC00000)>>22)+1;
+
+		dec->print("Label %u, offset 0x%06x", num, offset);
+		ifile->offset_add(rdoffset+offset, NET_ROAD_DEF);
 		dec->comment(NULL);
 	}
 }
Index: decode_rgn.cc
===================================================================
--- decode_rgn.cc	(revision 2)
+++ decode_rgn.cc	(working copy)
@@ -15,7 +15,7 @@
 
 void decode_rgn_header (class Decoder *dec_in, class ImgRGN *rgn_in)
 {
-	off_t soffset;
+	off_t soffset, hoffset;
 	rgn= rgn_in;
 	dec= dec_in;
 	img= dec->img;
@@ -24,8 +24,9 @@
 	net= (class ImgNET *) ifile->subfile_find("NET");
 
 	soffset= rgn->offset();
+	hoffset= rgn->h_offset();
 
-	img->seek(soffset);
+	img->seek(hoffset);
 
 	dec->set_outfile("RGN", "header");
 	dec->banner("RGN: Header");
@@ -150,9 +151,9 @@
 		word_t dx, dy;
 		string sinfo;
 
-		if ( indexed ) dec->comment("Point #%u", idx++);
+		dec->comment("Point #%u", idx++);
 		type= img->get_byte();
-		if ( has_subtype ) dec->print("Primary type %u", type);
+		dec->print("Primary type %u", type);
 
 		point_info= img->get_uint24();
 		has_subtype= (point_info & 0x800000);
@@ -230,10 +231,10 @@
 			lbl_in_net= lbl_info & 0x800000;
 			if ( lbl_in_net ) {
 				off_t netoff= net->roads_info.offset+
-					net->omult*lbloffset;
+					net->omult1*lbloffset;
 				ifile->offset_add(netoff, NET_ROAD_REC);
 				dec->print("Label at NET offset 0x%06x",
-					net->omult*lbloffset);
+					net->omult1*lbloffset);
 			} else {
 				dec->print("Label at LBL offset 0x%06x",
 					lbloffset);
Index: subfile.cc
===================================================================
--- subfile.cc	(revision 2)
+++ subfile.cc	(working copy)
@@ -10,8 +10,23 @@
 {
 }
 
+void ImgSubfile::set_header_offset (off_t offset_in)
+{
+	header_offset= offset_in;
+}
+
+void ImgSubfile::set_size (udword_t size_new)
+{
+	size= size_new;
+}
+
 off_t ImgSubfile::offset ()
 {
 	return imgfile_offset;
 }
 
+off_t ImgSubfile::h_offset ()
+{
+	return header_offset;
+}
+
Index: tre.cc
===================================================================
--- tre.cc	(revision 2)
+++ tre.cc	(working copy)
@@ -3,7 +3,7 @@
 ImgTRE::ImgTRE (class ImgFile *ifilein, off_t offset)
 {
 	ifile= ifilein;
-	imgfile_offset= offset;
+	header_offset= imgfile_offset= offset;
 	nsubdivisions= 0;
 	nlevels= 0;
 }
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to