Subversion Repositories mkgmap

Rev

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

/*
 * Copyright (C) 2008 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: 18-Jun-2008
 */

package uk.me.parabola.imgfmt.app.trergn;

/**
 * Class to calculate the values that occur at offset 9a in the TRE header.
 * As I don't know the purpose of these the naming is a bit arbitrary here...
 *
 * This was worked out in the display project, so see the TreCalc file
 * there for more history.  This is a cleaned up version of what was
 * written there.
 *
 * @author Steve Ratcliffe
 * @see <a href="http://svn.parabola.me.uk/display/trunk/src/test/display/TreCalc.java">TreCalc.java</a>
 */

public class MapValues {
        private final int mapId;
        private final int length;

        private final byte[][] values = new byte[4][8];

        // Converts the digits in the map id to the values seen in this section.
        private static final byte[] mapIdCodeTable = {
                        0, 1, 0xf, 5,
                        0xd, 4, 7, 6,
                        0xb, 9, 0xe, 8,
                        2, 0xa, 0xc, 3
        };

        // Used to work out the required offset that is applied to all the
        // digits of the values.
        private final int[] offsetMap = {
                        6, 7, 5, 11,
                        3, 10, 13, 12,
                        1, 15, 4, 14,
                        8, 0, 2, 9
        };

        public MapValues(int mapId, int headerLength) {
                this.mapId = mapId;
                this.length = headerLength;
        }

        /**
         * There are four values.  Get value n.
         * @param n Get value n, starting at 0 up to four.
         */

        public int value(int n) {
                byte[] out = values[n];

                int res = 0;
                for (int i = 0; i < 8; i++) {
                        res |= ((out[i] & 0xf) << (4 * (7 - i)));
                }
                return res;
        }

        public void calculate() {
                // Done in this order because the first and second depend on things
                // we have already calculated in three.
                calcThird();
                calcFourth();
                calcFirst();
                calcSecond();

                addOffset();
        }

        /**
         * Add an offset to all previously calculated values.
         */

        private void addOffset() {
                // To get the offset value we add up all the even nibbles of the map
                // number and transform via a table.
                int n = mapIdDigit(1) + mapIdDigit(3) + mapIdDigit(5) + mapIdDigit(7);

                int offset = offsetMap[n & 0xf];
                for (int i = 0; i < 4; i++) {
                        for (int j = 0; j < 8; j++) {
                                values[i][j] += offset;
                        }
                }
        }

        /**
         * This value is made from the third value, combined with the raw
         * map id values.
         */

        private void calcFirst() {
                byte[] out = values[0];
                byte[] v3 = values[3];

                // First bytes are the low bytes of the mapId, with the corresponding
                // value from value[3] added.
                out[0] = (byte) (mapIdDigit(4) + v3[0]);
                out[1] = (byte) (mapIdDigit(5) + v3[1]);
                out[2] = (byte) (mapIdDigit(6) + v3[2]);
                out[3] = (byte) (mapIdDigit(7) + v3[3]);

                // Copies of v3
                out[4] = v3[4];
                out[5] = v3[5];
                out[6] = v3[6];

                // Always (?) one more.  The one likely comes from some other
                // part of the header, but we don't know if or where.
                out[7] = (byte) (v3[7] + 1);
        }

        /**
         * This is made from various parts of the third value and the raw digits
         * from the map id.  There are two digits where the header length digits
         * are used (or that could be a coincidence, but it holds up well so far).
         */

        private void calcSecond() {
                byte[] out = values[1];
                byte[] v3 = values[3];

                // Just same as in v3
                out[0] = v3[0];
                out[1] = v3[1];

                int h1 = length >> 4;
                int h2 = length;
                out[2] = (byte) ((v3[2] + h1) & 0xf);
                out[3] = (byte) ((v3[3] + h2) & 0xf);

                // The following are the sum of individual nibbles in U3 and the
                // corresponding nibble in the top half of mapId.
                out[4] = (byte) (v3[4] + mapIdDigit(0));
                out[5] = (byte) (v3[5] + mapIdDigit(1));
                out[6] = (byte) (v3[6] + mapIdDigit(2));
                out[7] = (byte) (v3[7] + mapIdDigit(3));
        }

        /**
         * This is made of the hex digits of the map id in a given order
         * translated according to a given table of values.
         */

        private void calcThird() {
                byte[] out = values[2];
                for (int i = 0; i < 8; i++) {
                        int n = mapIdDigit(i);
                        out[(i ^ 1)] = mapIdCodeTable[n];
                }
        }

        /**
         * This is just a copy of the third value.
         */

        private void calcFourth() {
                System.arraycopy(values[2], 0, values[3], 0, values[3].length);
        }

        /**
         * Extract the given nibble of the map id.  0 is the highest four bits.
         * @param i The nibble number, 0 most significant, 7 the least.
         * @return The given nibble of the map id.
         */

        private int mapIdDigit(int i) {
                return (mapId >>> (4 * (7 - i))) & 0xf;
        }
}