Subversion Repositories mkgmap

Rev

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

/*
 * Copyright (C) 2007 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 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.
 *
 *
 * Author: Steve Ratcliffe
 * Create date: 23-Sep-2007
 */

package uk.me.parabola.tdbfmt;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;

import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.io.EndOfFileException;
import uk.me.parabola.io.StructuredInputStream;
import uk.me.parabola.log.Logger;

/**
 * The TDB file.  See the package documentation for more details.
 *
 * @author Steve Ratcliffe
 */

public class TdbFile {
        private static final Logger log = Logger.getLogger(TdbFile.class);

        public static final int TDB_V407 = 407;

        private static final int BLOCK_OVERVIEW = 0x42;
        private static final int BLOCK_HEADER = 0x50;
        private static final int BLOCK_COPYRIGHT = 0x44;
        private static final int BLOCK_DETAIL = 0x4c;
        private static final int BLOCK_R = 0x52;
        private static final int BLOCK_T = 0x54;

        // The version number of the TDB format
        private int tdbVersion;

        // The blocks that go to make up the file.
        private HeaderBlock headerBlock;
        private CopyrightBlock copyrightBlock = new CopyrightBlock();
        private OverviewMapBlock overviewMapBlock;
        private final List<DetailMapBlock> detailBlocks = new ArrayList<DetailMapBlock>();
        private final RBlock rblock = new RBlock();
        private final TBlock tblock = new TBlock();
        private String overviewDescription;

        public TdbFile() {
        }

        public TdbFile(int tdbVersion) {
                this.tdbVersion = tdbVersion;
        }

        /**
         * Read in a TDB file from the disk.
         *
         * @param name The file name to load.
         * @return A TdbFile instance.
         * @throws IOException For problems reading the file.
         */

        public static TdbFile read(String name) throws IOException {
                TdbFile tdb = new TdbFile();

                InputStream is = new BufferedInputStream(new FileInputStream(name));

                try {
                        StructuredInputStream ds = new StructuredInputStream(is);
                        tdb.load(ds);
                } finally {
                        is.close();
                }

                return tdb;
        }

        public void setProductInfo(int familyId, int productId,
                        short productVersion, String seriesName, String familyName, String overviewDescription,
                        byte enableProfile)
        {
                headerBlock = new HeaderBlock(tdbVersion);
                headerBlock.setFamilyId((short) familyId);
                headerBlock.setProductId((short) productId);
                headerBlock.setProductVersion(productVersion);
                headerBlock.setSeriesName(seriesName);
                headerBlock.setFamilyName(familyName);
                headerBlock.setEnableProfile(enableProfile);
                this.overviewDescription = overviewDescription;
        }

        public void setCodePage(int codePage) {
                headerBlock.setCodePage(codePage);
        }

        /**
         * Add a copyright segment to the file.
         * @param msg The message to add.
         */

        public void addCopyright(String msg) {
                CopyrightSegment seg = new CopyrightSegment(CopyrightSegment.CODE_COPYRIGHT_TEXT_STRING, 3, msg);
                copyrightBlock.addSegment(seg);
        }

        /**
         * Set the overview information.  Basically the overall size of the map
         * set.
         * @param bounds The bounds for the map.
         */

        public void setOverview(Area bounds, String number) {
                overviewMapBlock = new OverviewMapBlock();
                overviewMapBlock.setArea(bounds);
                overviewMapBlock.setMapName(number);
                overviewMapBlock.setDescription(overviewDescription);
        }

        /**
         * Add a detail block.  This describes and names one of the maps in the
         * map set.
         * @param detail The detail to add.
         */

        public void addDetail(DetailMapBlock detail) {
                detailBlocks.add(detail);
        }

        public void write(String name) throws IOException {
                CheckedOutputStream stream = new CheckedOutputStream(
                                new BufferedOutputStream(new FileOutputStream(name)),
                                new CRC32());

                if (headerBlock == null || overviewMapBlock == null)
                        throw new IOException("Attempting to write file without being fully set up");

                try {
                        Block block = new Block(BLOCK_HEADER);
                        headerBlock.write(block);
                        block.write(stream);

                        block = new Block(BLOCK_COPYRIGHT);
                        copyrightBlock.write(block);
                        block.write(stream);

                        if (tdbVersion >= TDB_V407) {
                                block = new Block(BLOCK_R);
                                rblock.write(block);
                                block.write(stream);
                        }

                        block = new Block(BLOCK_OVERVIEW);
                        overviewMapBlock.write(block);
                        block.write(stream);

                        for (DetailMapBlock detail : detailBlocks) {
                                block = new Block(BLOCK_DETAIL);
                                detail.write(block);
                                block.write(stream);
                        }

                        if (tdbVersion >= TDB_V407) {
                                tblock.setSum(stream.getChecksum().getValue());

                                block = new Block(BLOCK_T);
                                tblock.write(block);
                                block.write(stream);
                        }
                } finally {
                        stream.close();
                }
        }

        /**
         * Load from the given file name.
         *
         * @param ds The stream to read from.
         * @throws IOException For problems reading the file.
         */

        private void load(StructuredInputStream ds) throws IOException {

                while (!ds.testEof()) {
                        Block block = readBlock(ds);

                        switch (block.getBlockId()) {
                        case BLOCK_HEADER:
                                headerBlock = new HeaderBlock(block);
                                log.info("header block seen", headerBlock);
                                break;
                        case BLOCK_COPYRIGHT:
                                log.info("copyright block");
                                copyrightBlock = new CopyrightBlock(block);
                                break;
                        case BLOCK_OVERVIEW:
                                overviewMapBlock = new OverviewMapBlock(block);
                                log.info("overview block", overviewMapBlock);
                                break;
                        case BLOCK_DETAIL:
                                DetailMapBlock db = new DetailMapBlock(block);
                                log.info("detail block", db);
                                detailBlocks.add(db);
                                break;
                        default:
                                log.warn("Unknown block in tdb file");
                                break;
                        }
                }

        }

        /**
         * The file is divided into blocks.  This reads a single block.
         *
         * @param is The input stream.
         * @return A block from the file.
         * @throws IOException For problems reading the file.
         */

        private Block readBlock(StructuredInputStream is) throws IOException {
                int blockType = is.read();
                if (blockType == -1)
                        throw new EndOfFileException();
                int blockLength = is.read2();

                byte[] body = new byte[blockLength];
                int n = is.read(body);
                if (n < 0)
                        throw new IOException("failed to read block");

                return new Block(blockType, body);
        }

        public int getTdbVersion() {
                return headerBlock.getTdbVersion();
        }
}