Rev 438 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
#include <math.h>
#include "garminimg.h"
#include "decoder.h"
#include "decode_img.h"
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;
static class Decoder *dec;
static class ImgLBL *lbl;
void decode_lbl_header (class Decoder *dec_in, class ImgLBL *lbl_in)
{
udword_t length;
uword_t rsize;
off_t offset, soffset, hoffset;
lbl= lbl_in;
dec= dec_in;
img= dec->img;
ifile= lbl->ifile;
soffset= lbl->offset();
hoffset= lbl->h_offset();
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());
if (length) ifile->offset_add(offset, LBL_LABELS);
dec->print("Label data offsets are x%u",
lbl->omult= int(pow(2.0,img->get_byte())));
dec->print("Label coding %d", lbl->encoding= img->get_byte());
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",
length= img->get_udword());
dec->print("Country record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_COUNTRY_DEF);
lbl->country_info.length= length;
lbl->country_info.offset= offset;
lbl->country_info.rsize= rsize;
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",
length= img->get_udword());
dec->print("Region record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_REGION_DEF);
lbl->region_info.length= length;
lbl->region_info.offset= offset;
lbl->region_info.rsize= rsize;
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",
length= img->get_udword());
dec->print("City record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_CITY_DEF);
lbl->city_info.length= length;
lbl->city_info.offset= offset;
lbl->city_info.rsize= rsize;
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);
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("POI data offsets are x%u",
lbl->poi_omult= int(pow(2.0,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_hwyexit, has_tides,
has_unkn;
char mask= 0x1;
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 ( has_street_num ) {
s_flags+= "street_num,";
lbl->poi_mask.street_num= mask;
mask*= 2;
}
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->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;
lbl->poiprop_info.offset= offset;
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",
length= img->get_udword());
dec->print("Unknown2 record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_UNKN2);
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",
length= img->get_udword());
dec->print("Zip record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_ZIP_DEF);
lbl->zip_info.length= length;
lbl->zip_info.offset= offset;
lbl->zip_info.rsize= rsize;
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",
length= img->get_udword());
dec->print("Highway record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_HWY_DEF);
lbl->hwy_info.length= length;
lbl->hwy_info.offset= offset;
lbl->hwy_info.rsize= rsize;
dec->print("", img->get_udword());
// LBL section 10
offset= img->get_udword()+soffset;
dec->print("Exit services at 0x%06lx", offset);
dec->print("Exit services length %lu bytes",
length= img->get_udword());
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("Exit list at 0x%06lx", offset);
dec->print("Exit list length %lu bytes",
length= img->get_udword());
dec->print("Exit list record size %u bytes",
rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_EXIT_LST);
lbl->exitlist_info.length= length;
lbl->exitlist_info.offset= offset;
lbl->exitlist_info.rsize= rsize;
// LBL section 12?
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->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",
length= img->get_udword());
dec->print("Unknown3 record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_UNKN3);
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",
length= img->get_udword());
dec->print("Unknown4 record size %u bytes", rsize= img->get_uword());
if (length) ifile->offset_add(offset, LBL_UNKN4);
dec->print("", img->get_uword());
// offset= ifile->offset_next(img->tell());
offset= soffset + lbl->hlen;
if ( img->tell() < offset ) dec->print("???",
img->get_string(offset - img->tell()).c_str());
dec->banner("LBL: End Header");
}
void decode_lbl_body ()
{
off_t soffset= lbl->offset()+lbl->hlen;
off_t eoffset= lbl->offset()+lbl->size;
off_t noffset;
unsigned int type;
// 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.
decode_lbl_labels();
// Countries, regions, cities, zips in that order.
decode_lbl_country_def();
decode_lbl_region_def();
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 offset, end;
string label;
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;
label= lbl->label_parse_abs(offset);
lbloffset= (offset - lbl->label_info.offset)/lbl->omult;
dec->comment("Offset 0x%06x", lbloffset);
ifile->label_store(lbloffset, label);
img->sbuffer_recall();
dec->print("%s", label.c_str());
offset= img->tell();
if ( lbl->omult > 1 ) {
n= (offset-lbl->label_info.offset) % lbl->omult;
if ( n ) {
dec->print(NULL,
img->get_string(lbl->omult-n).c_str());
offset= img->tell();
}
}
dec->comment(NULL);
}
}
void decode_lbl_country_def ()
{
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;
loffset= img->get_uint24();
dec->print("Country %u: LBL offset 0x%06x", n, loffset);
country= ifile->label_get(loffset);
dec->comment("%s", country.c_str());
// img->country(n, &label);
}
dec->comment(NULL);
}
void decode_lbl_region_def ()
{
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;
string label;
cidx= img->get_uword();
dec->print("In country %u", cidx);
loffset= img->get_uint24();
dec->print("Region %u: LBL offset 0x%06x", n, loffset);
label= ifile->label_get(loffset);
dec->comment("%s", label.c_str());
ifile->region_add(n, label, cidx);
}
}
void decode_lbl_city_def ()
{
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;
bool pref;
string label;
cdata= img->get_uint24();
img->sbuffer_set();
cinfo= img->get_uword();
img->sbuffer_swap();
ridx= (cinfo & 0x3FFF);
pref= (cinfo & 0x8000);
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);
label= ifile->label_get(loffset);
ifile->city_add(n, label, ridx);
}
img->sbuffer_recall();
dec->print("in region %u", ridx);
if ( pref ) dec->comment("is point offset");
else dec->comment("%s", ifile->city_get(n).c_str());
dec->comment(NULL);
}
}
void decode_lbl_zip ()
{
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;
dec->print("Zip %u label at 0x%06x", n, offset);
dec->comment("%s", ifile->label_get(offset).c_str());
ifile->zip_add(n, label);
}
}
void decode_lbl_poiprop ()
{
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_hwyexit, has_tides,
has_unkn;
poi_data= img->get_uint24();
lbloffset= (poi_data & 0x3FFFFF);
override= (poi_data & 0x800000);
dec->print("Label offset 0x%06x", lbloffset);
dec->comment("%s", ifile->label_get(lbloffset).c_str());
if ( override ) {
flags= img->get_byte();
dec->print("%s override flags",
img->base(flags, 2, 8).c_str());
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;
} else {
flags= lbl->global_poi_flags();
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;
}
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_hwyexit ) s_flags+= "hwyexit,";
if ( has_tides ) s_flags+= "tides,";
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('-');
if ( snum.empty() ) {
udword_t mpoffset;
string::size_type idx;
dec->print("street 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);
snum= ifile->label_get(mpoffset);
idx= snum.find("-6", 0);
if ( idx != string::npos )
snum.replace(idx, 2, ", Suite ");
dec->comment("Address %s", snum.c_str());
} else dec->print("Street num %s", snum.c_str());
}
if ( has_street ) {
lbloffset= img->get_uint24();
dec->print("Street lbl at 0x%06x", lbloffset);
dec->comment("%s", ifile->label_get(lbloffset).c_str());
}
if ( has_city ) {
udword_t cidx;
if ( ifile->ncities() > 0xFF ) cidx= img->get_uword();
else cidx= img->get_byte();
dec->print("City idx %lu", cidx);
dec->comment("%s", ifile->city_get(cidx).c_str());
}
if ( has_zip ) {
udword_t zidx;
if ( ifile->nzips() > 0xFF ) zidx= img->get_uword();
else zidx= img->get_byte();
dec->print("Zip idx %lu", zidx);
dec->comment("%s", ifile->zip_get(zidx).c_str());
}
if ( has_phone ) {
string phn= img->get_base11str('-');
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_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->poi_omult && img->tell() < eos ) {
dec->print(NULL, img->get_byte());
}
dec->comment(NULL);
}
}
void decode_lbl_hwy_def ()
{
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) {
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);
}
}