Subversion Repositories display

Rev

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

package test.display;

import java.io.BufferedOutputStream;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
import uk.me.parabola.imgfmt.app.ImgFileReader;
import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
import uk.me.parabola.imgfmt.app.trergn.Subdivision;
import uk.me.parabola.imgfmt.app.trergn.TREFileReader;
import uk.me.parabola.imgfmt.app.trergn.Zoom;
import uk.me.parabola.imgfmt.fs.DirectoryEntry;
import uk.me.parabola.imgfmt.fs.FileSystem;
import uk.me.parabola.imgfmt.fs.ImgChannel;
import uk.me.parabola.imgfmt.sys.FileImgChannel;
import uk.me.parabola.imgfmt.sys.ImgFS;

import test.elements.Line;
import test.files.NetFile;
import test.files.Nod2Record;
import test.files.NodFile;
import test.files.RgnFile;
import test.files.RoadData;
import test.files.RouteNode;
import test.files.Segment;

/**
 * Common code for files that have the 'common header' in a .img file.
 */

public abstract class CommonDisplay {
        public static final int COMMON_HEADER_LEN = 21;

        // You will always have a reader.
        protected ImgFileReader reader;

        // You may not have a filesystem.
        private FileSystem fs;

        protected PrintStream outStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)));
        private int headerLen;
        protected long filelen;

        // The sections in the file, if any.
        protected SectList sections = new SectList();

        protected LBLFileReader lbl;
        protected TREFileReader tre;
        protected RgnFile rgn;
        protected NetFile net;
        protected NodFile nod;
        protected int citySize;
        protected int zipSize;

        protected abstract void print();

        protected void readCommonHeader() {

                Displayer d = new Displayer(reader);
                d.setTitle("Common Header");

                headerLen = d.charValue("Header length %d");
                d.stringValue(10, "File type %s");

                d.byteValue("???");
                d.byteValue("Set if locked");

                DisplayItem item = d.rawItem(7);
        Date date = Utils.makeCreationTime(item.getBytes());
        DateFormat df = new SimpleDateFormat("HH:mm:ss d MMM yyyy");
        item.addText(df.format(date));

        d.print(outStream);
        }

        protected void readHeaderLen() {
                reader.position(0);
                headerLen = reader.getChar();
                reader.position(COMMON_HEADER_LEN);
        }

        /**
         * Read the common combination offset + size (+ record size) in file headers.
         * Utility function for subclasses.
         *
         * @param d The {@link Displayer} to use.
         * @param name The name of the sub-file.
         * @param number The section number.
         * @param hasRecSize There is a record size to be read.
         * @param hasMagic Has an 4 byte integer value following the header information. Otherwise
         * false and any extra values must be read explicitly.
         * @return The section information.  It has also been saved for retrieval with getSection.
         */

        protected Section readSection(Displayer d, String name, int number, boolean hasRecSize, boolean hasMagic) {
                assert number != 0;

                d.gap();
               
                int start = d.intValue(name + " at offset %#08x");
                int len = d.intValue(name + " length %d");
                Section section = new Section(name, start, len);
                d.item().addText("End of section %08x, len %#08x", start + len, len);

                if (hasRecSize) {
                        int recordSize = d.charValue(name + " record size %02x");
                        if (recordSize != 0) {
                                //assert len % recordSize == 0 : "sect" + number + ", len=" + len + ", recsize=" + recordSize;
                                d.item().addText("Number of records %d", len / recordSize);
                                if (len % recordSize != 0)
                                        d.item().addText("FRACTIONAL RECORD");
                        }
                        section.setRecordSize(recordSize);
                }

                if (hasMagic) {
                        int magic = d.intValue(name + " header flags %04x");
                        section.setMagic(magic);
                }

                while (sections.size() < number-1)
                        sections.add(null);
                sections.add(number-1, section);
                return section;
        }

        protected Section getSection(int n) {
                assert n != 0;
                return sections.get(n-1);
        }

        protected int numberOfSections() {
                return sections.size();
        }


        /**
         * This is used when you want to open a plain file.
         * @param name The name of the file to open.
         */

        protected void display(String name) {
                RandomAccessFile raf = null;
                try {
                        raf = new RandomAccessFile(name, "r");
                        filelen = raf.length();
                        ImgChannel chan = new FileImgChannel(raf.getChannel());
                        this.reader = new BufferedImgFileReader(chan);
                        print();
                        outStream.flush();
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open file: " + name);
                } catch (IOException e) {
                        System.err.println("Could not get file size or read file " + name);
                } finally {
                        if (raf != null) {
                                try {
                                        raf.close();
                                } catch (IOException e) {
                                        // ok
                                }
                        }
                }
        }

        /**
         * This is used to open a file within an img file.
         *
         * @param name The name of the .img file.
         * @param fileExt The file to get.  It is found by extension.
         */

        protected void display(String name, String fileExt) {
                if (name.toLowerCase().endsWith(fileExt.toLowerCase())) {
                        display(name);
                        return;
                }
               
                try {
                        fs = ImgFS.openFs(name);
                        ImgChannel chan = findFile(fileExt);
                        this.reader = new BufferedImgFileReader(chan);
                        print();
                        outStream.flush();
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open file: " + name);
                } finally {
                        if (fs != null) {
                                fs.close();
                        }
                }
        }

        protected ImgChannel findFile(String fileExt) throws FileNotFoundException {
                if (fs == null)
                        throw new FileNotFoundException("Not an img file");
               
                List<DirectoryEntry> entries = fs.list();
                ImgChannel chan = null;
                for (DirectoryEntry ent : entries) {
                        if (ent.getExt().equals(fileExt)) {
                                filelen = ent.getSize();
                                chan = fs.open(ent.getFullName(), "r");
                        }
                }

                if (chan == null)
                        throw new FileNotFoundException("No file with " + fileExt + " extension");
               
                return chan;
        }

        protected void openLbl() {
                if (lbl != null)
                        return;
                try {
                        ImgChannel chan = findFile("LBL");
                        lbl = new LBLFileReader(chan);

                        int numCities = lbl.getCities().size();
                        if (numCities > 255)
                                citySize = 2;

                        int numZips = lbl.getZips().size();
                        if (numZips > 255)
                                zipSize = 2;
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open LBL file");
                }
        }

        protected String fetchLabel(int laboff) {
                if (lbl == null)
                        return "";
                return lbl.fetchLabel(laboff).getText();
        }


        protected void openTre() {
                if (tre != null)
                        return;

                try {
                        ImgChannel chan = findFile("TRE");
                        tre = new TREFileReader(chan);
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open TRE file");
                }
        }

        protected void openRgn() {
                if (rgn != null)
                        return;

                if (lbl == null)
                        openLbl();
                if (net == null)
                        openNet();

                try {
                        ImgChannel chan = findFile("RGN");
                        rgn = new RgnFile(chan);
                        rgn.setLblFile(lbl);
                        rgn.setNetFile(net);
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open RGN file");
                }
        }

        protected void openNet() {
                if (net != null)
                        return;

                if (lbl == null)
                        openLbl();

                try {
                        ImgChannel chan = findFile("NET");
                        net = new NetFile(new BufferedImgFileReader(chan));
                        net.setLableFile(lbl);
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open NET file");
                }
        }

        protected void openNod() {
                if (nod != null)
                        return;

                try {
                        ImgChannel chan = findFile("NOD");
                        nod = new NodFile(new BufferedImgFileReader(chan));
                } catch (FileNotFoundException e) {
                        System.err.println("Could not open NOD file");

                }
        }

        protected void initRoads() {
                if (nod == null)
                        openNod();

                Zoom[] levels = tre.getMapLevels();
                Subdivision[] subdivisions = tre.subdivForLevel(levels[levels.length - 1].getLevel());

                Map<Integer, Line> lines = new HashMap<>();
                Set<Integer> netOffsets = new HashSet<>();

                // Fetch all lines and save all net offsets found.
                for (Subdivision sub : subdivisions) {
                        for (Line line : rgn.linesForSubdiv(sub)) {
                                int divNum = line.getDivAndNum();
                                lines.put(divNum, line);
                                if (line.hasNet()) {
                                        netOffsets.add(line.getNetOffset());
                                }
                        }
                }

                // Go through all net offsets and set the line information into the road data.
                for (int noff : netOffsets) {
                        RoadData road = net.getRoad(noff);

                        for (Segment seg : road.getSegments()) {
                                int divNum = seg.getDivAndNum();
                                Line line = lines.get(divNum);
                                assert line != null;

                                seg.setLine(line);
                        }

                        int offsetNod2 = road.getOffsetNod2();
                        Nod2Record netInfo = nod.getNod2(offsetNod2);
                        netInfo.setRoadData(road);
                        road.setNod2(netInfo);

            RouteNode node = netInfo.getNode();
                        if (node == null) {
                                System.out.printf("Could not find node for road %x nod2=%x\n",
                                                noff,
                                                offsetNod2);
                                continue;
                        }
                        node.setRoad(road);
        }
        }

        protected void setOutStream(PrintStream outStream) {
                this.outStream = outStream;
        }

        protected int getHeaderLen() {
                return headerLen;
        }

        protected void analyze(PrintStream outStream) {
                sections.analyze(outStream);
        }

        protected void addSection(Section section) {
                sections.add(section);
        }
}