Subversion Repositories display

Rev

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);
        }
}