/*
* 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;
}
}