Subversion Repositories display

Rev

Rev 287 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <math.h>
#include <stdlib.h>
#include "imgtypes.h"
#include "garminimg.h"
#include "decoder.h"
#include "decode_img.h"

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_sorted ();

void decode_net_header (class Decoder *dec_in, class ImgNET *net_in)
{
        udword_t length, offset;
        uword_t rsize;
        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(hoffset);

        dec->set_outfile("NET", "header");
        dec->banner("NET: Header");
        decode_common_header(dec, net);

        dec->print("Road defs at offset 0x%08x",
                offset= img->get_udword()+soffset);
        dec->print("Road defs length %ld bytes",
                length= img->get_udword());
        ifile->offset_add(offset, NET_ROAD_DEF);
        net->roads_info.offset= offset;
        net->roads_info.length= length;

        dec->print("Road record offsets are x%u",
                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("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;

        dec->print("Unknown2 at offset 0x%08x",
                offset= img->get_udword()+soffset);
        dec->print("Unknown2 length %ld bytes",
                length= img->get_udword());
        dec->print("Unknown2 record size %u bytes",
                rsize= img->get_uword());
        ifile->offset_add(offset, NET_UNKN1);
        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());
        dec->print("???", img->get_byte());
        dec->print("???", img->get_udword());
        dec->print("???", img->get_udword());
        dec->print("???", img->get_udword());

        dec->banner("NET: End Header");
}

void decode_net_body ()
{
        // Sorted road list

        decode_net_sorted ();

        // Parse road information first.

        decode_net_roads ();

}

void decode_net_roads ()
{
        // These have variable-length records that have not been
        // deciphered.  So, use the offsets that we created when
        // parsing RGN to determine the start of each record.

        off_t soffset= net->roads_info.offset;
        off_t eoffset= soffset+net->roads_info.length;

        img->seek(net->roads_info.offset);
        dec->set_outfile("NET", "roads");
        dec->banner("NET: Road definitions?");

        while ( img->tell() < eoffset ) {
                udword_t lbloffset, roadinfo;
                double roadlen;
                byte_t data, flags;
                bool repeat;
                off_t noffset;
                int i, n, lcount;
                unsigned int otype;
                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 ) {
                        fprintf(stderr, "Not a known offset at 0x%08x",
                                img->tell());
                        exit(1);
                }

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

                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= lcount= 0;
                while ( repeat ) {
                        int cnt;

                        data= img->get_byte();
                        repeat= !(data&0x80);
                        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",
                                (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;

                stream= img->get_string(noffset-img->tell());
                dec->print("%u byte stream", stream.length());
        }
}

void decode_net_sorted ()
{
        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->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);

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