Subversion Repositories display

Rev

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

/*
 * Copyright (C) 2014 Steve Ratcliffe
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 or
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package test.files;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import uk.me.parabola.imgfmt.app.ImgFileReader;
import uk.me.parabola.imgfmt.app.Label;
import uk.me.parabola.imgfmt.app.lbl.City;
import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
import uk.me.parabola.imgfmt.app.lbl.Zip;
import uk.me.parabola.imgfmt.app.net.NETHeader;
import uk.me.parabola.imgfmt.app.net.RoadDef;

/**
 * @author Steve Ratcliffe
 */

public class NetFile {
        private final NETHeader netHeader = new NETHeader();

        private final ImgFileReader reader;
        private LBLFileReader labels;

        private List<City> cities;
        private int citySize;
        private List<Zip> zips;
        private int zipSize;

        private final Map<Integer, RoadData> roadCache = new HashMap<>();

        public NetFile(ImgFileReader reader) {
                this.reader = reader;

                netHeader.readHeader(reader);
        }

        /**
         * Get the list of roads from the net section.
         * <p/>
         * Saving the bare minimum that is needed, please improve.
         *
         * @return A list of RoadDefs. Note that currently not everything is
         * populated in the road def so it can't be written out as is.
         */

        public RoadData getRoad(int offset) {
                RoadData road = roadCache.get(offset);
                if (road != null)
                        return road;

                road = new RoadData();
                road.setOffset(offset);

                int start = netHeader.getRoadDefinitionsStart();

                reader.position(start + offset);

                readLabels(road);
                byte netFlags = reader.get();
                road.setLength(reader.getu3());

                int[] counts = new int[24];
                int maxLevel = 0;
                while (maxLevel < 24) {
                        int n = reader.get();
                        counts[maxLevel++] = (n & 0x7f);
                        if ((n & 0x80) != 0)
                                break;
                }

                for (int level = 0; level < maxLevel; level++) {
                        int c = counts[level];
                        for (int j = 0; j < c; j++) {
                                int idx = reader.get();
                                int div = reader.getChar();
                                if (level == 0) {
                                        Segment seg = new Segment();
                                        seg.setDiv(div);
                                        seg.setIdx(idx);
                                        road.addSegment(seg);
                                }
                        }
                }

                if ((netFlags & RoadDef.NET_FLAG_ADDRINFO) != 0) {
                        char flags2 = reader.getChar();

                        int zipFlag = (flags2 >> 10) & 0x3;
                        int cityFlag = (flags2 >> 12) & 0x3;
                        int numberFlag = (flags2 >> 14) & 0x3;

                        road.setZip(fetchZipCity(reader, zipFlag, zips, zipSize));
                        road.setCity(fetchZipCity(reader, cityFlag, cities, citySize));

                        fetchNumber(reader, numberFlag);
                }

                if ((netFlags & RoadDef.NET_FLAG_NODINFO) != 0) {
                        int nodFlags = reader.get();
                        int nbytes = nodFlags & 0x3;
                        if (nbytes > 0) {
                                int offsetNod2 = reader.getUint(nbytes + 1);
                                road.setOffsetNod2(offsetNod2);
                        }
                }

                roadCache.put(offset, road);
                return road;
        }

        /**
         * Fetch a zip or a city.
         *
         * @param <T> Can be city or zip.
         * @return The found City or Zip.
         */

        private <T> T fetchZipCity(ImgFileReader reader, int flag, List<T> list, int size) {
                T item = null;
                if (flag == 2) {
                        // fetch city/zip index
                        int ind = (size == 2) ? reader.getChar() : (reader.get() & 0xff);
                        if (ind != 0)
                                item = list.get(ind - 1);
                } else if (flag == 3) {
                        // there is no item
                } else if (flag == 0) {
                        // Skip over these
                        reader.get(reader.get() & 0xff);
                } else if (flag == 1) {
                        // Skip over these
                        int n = reader.getChar();
                        reader.get(n);
                } else {
                        assert false : "flag is " + flag;
                }
                return item;
        }

        /**
         * Fetch a block of numbers.
         *
         * @param reader The reader.
         * @param numberFlag The flag that says how the block is formatted.
         */

        private void fetchNumber(ImgFileReader reader, int numberFlag) {
                int n = 0;
                if (numberFlag == 0) {
                        n = reader.get() & 0xff;
                } else if (numberFlag == 1) {
                        n = reader.getChar();
                } else if (numberFlag == 3) {
                        // There is no block
                        return;
                } else {
                        // Possible but don't know what to do in this context
                        assert false;
                }
                if (n > 0)
                        reader.get(n);
        }

        private void readLabels(RoadData road) {
                for (int i = 0; i < 4; i++) {
                        int lab = reader.getu3();
                        assert labels!=null;
                        Label label = labels.fetchLabel(lab & 0x7fffff);
                        road.addLabel(label);
                        if ((lab & 0x800000) != 0)
                                break;
                }
        }

        public void setLableFile(LBLFileReader labels) {
                this.labels = labels;

                cities = labels.getCities();
                citySize = cities.size() > 255? 2: 1;

                zips = labels.getZips();
                zipSize = zips.size() > 255 ? 2 : 1;
        }
}