/*
* 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: Dec 16, 2007
*/
package test.display;
import java.io.FileNotFoundException;
import java.util.Formatter;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.BitReader;
import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
import uk.me.parabola.imgfmt.app.ImgFileReader;
import uk.me.parabola.imgfmt.app.trergn.TREFileReader;
import uk.me.parabola.imgfmt.app.trergn.TREHeader;
import uk.me.parabola.imgfmt.fs.ImgChannel;
import uk.me.parabola.mkgmap.general.LevelInfo;
/**
* Standalone program to display the RGN file.
*
* @author Steve Ratcliffe
*/
public class RgnDisplay
extends CommonDisplay
{
// private static final Logger log = Logger.getLogger(CommonDisplay.class);
private static final int FLAG_NETINFO = 0x800000
;
private static final int FLAG_EXTRA = 0x400000
;
private static final int MASK_LABEL = 0x3fffff
;
private int rgnStart
;
private Section levels
;
private Section subdivs
;
protected final LevelInfo
[] linfo =
new LevelInfo
[24];
protected final Subdiv
[][] divinfo =
new Subdiv
[24][];
protected void print
() {
readCommonHeader
();
openLbl
();
readHeader
();
readBody
();
}
private void readBody
() {
openTre
();
Displayer d =
new Displayer
(reader
);
d.
setTitle("RGN body");
d.
print(outStream
);
for (int i =
23; i
>=
0; i--
) {
LevelInfo li = linfo
[i
];
if (li ==
null)
continue;
int level = li.
getLevel();
for (Subdiv sd : divinfo
[level
])
printDiv
(sd
);
}
}
/**
* We probably don't need this now that tre has a method to read subdivisions.
*/
protected void openTre
() {
ImgChannel chan
;
try {
chan = findFile
("TRE");
tre =
new TREFileReader
(chan
);
} catch (FileNotFoundException e
) {
System.
err.
println("Could not open TRE file");
return;
}
TREHeader header =
(TREHeader
) tre.
getHeader();
int pos = header.
getMapLevelsPos();
int size = header.
getMapLevelsSize();
levels =
new Section
("Levels", pos, size
);
levels.
setRecordSize(4);
pos = header.
getSubdivPos();
size = header.
getSubdivSize();
subdivs =
new Section
("subdivs", pos, size
);
readLevel
(new BufferedImgFileReader
(chan
));
}
/**
* Print the section of the rgn file that belongs to the given subdiv.
* @param subdiv The subdiv. This will contain start and end points in the rgn file.
*/
private void printDiv
(Subdiv subdiv
) {
Displayer d =
new Displayer
(reader
);
d.
setTitle("Level " + subdiv.
getLevel() +
", Subdiv " + subdiv.
getNumber());
int offset = subdiv.
getRgnOffset();
reader.
position(rgnStart + offset
);
d.
setSectStart(rgnStart+offset
);
// Although we have start and end points, this is further split into areas
// for points, lines and polygons etc.
int n = subdiv.
numberOfPointers();
int[] pointers =
new int[n+
2];
pointers
[0] = rgnStart + offset +
(2 * n
);
for (int i =
0; i
< n
; i++
) {
pointers
[i +
1] = rgnStart + offset +
(int) d.
charValue("Pointer 0x%x");
}
pointers
[n +
1] = rgnStart + subdiv.
getEndRgnOffset();
d.
item().
addText("final at %x, (end %x)", pointers
[n +
1], subdiv.
getEndRgnOffset());
int count =
0;
if (subdiv.
hasPoint()) {
displayPoints
(d, subdiv, pointers, count
);
count++
;
}
if (subdiv.
hasIndPoint()) {
displayPoints
(d, subdiv, pointers, count
);
count++
;
}
if (subdiv.
hasLine()) {
displayLines
(d, subdiv, pointers, count
);
count++
;
}
if (subdiv.
hasShape()) {
displayLines
(d, subdiv, pointers, count
);
}
d.
print(outStream
);
}
private void displayLines
(Displayer d, Subdiv subdiv,
int[] pointers,
int count
) {
d.
item().
addText("line start %x to %x", pointers
[count
], pointers
[count+
1]);
reader.
position(pointers
[count
]);
int lineNo =
1;
while (reader.
position() < pointers
[count+
1]) {
DisplayItem item = d.
item();
int type = item.
setBytes(reader.
get());
item.
addText("Line %d", lineNo++
);
item.
addText("Type 0x%x", type
& 0x7f
);
//int type = d.byteValue("Type %x");
boolean twoByteBitLength =
false;
if ((type
& 0x80
) !=
0)
twoByteBitLength =
true;
item = d.
item();
int labval = reader.
get3();
item.
setBytes3(labval
);
int off = labval
& MASK_LABEL
;
boolean extra =
(labval
& FLAG_EXTRA
) !=
0;
boolean netinfo =
(labval
& FLAG_NETINFO
) !=
0;
if (netinfo
)
item.
addText("NET offset: 0x%06x", off
);
else
item.
addText("Label offset: 0x%06x (%s)", off, fetchLabel
(off
));
if (extra
)
d.
item().
addText("extra bit");
short dlon = d.
shortValue("Long delta %d");
short dlat = d.
shortValue("Lat delta %d");
int currLat = fixDelta
(subdiv, subdiv.
getLatitude(), dlat
);
int currLon = fixDelta
(subdiv, subdiv.
getLongitude(), dlon
);
d.
item().
addText("Start point %.5f,%.5f",
Utils.
toDegrees(currLat
),
Utils.
toDegrees(currLon
));
int bslen = twoByteBitLength
? d.
charValue("Bitstream length (2 byte) %d")
: d.
byteValue("Bitstream length %d") & 0xff
;
int base = d.
byteValue("Base %x");
int xbase =
2;
int n = base
& 0xf
;
if (n
<=
9)
xbase += n
;
else
xbase +=
(2 * n
) -
9;
n =
(base
>>> 4) & 0xf
;
int ybase =
2;
if (n
<=
9)
ybase += n
;
else
ybase +=
(2 * n
) -
9;
if (bslen ==
0) {
d.
item().
addText("bitstream length 0!");
d.
gap();
break;
}
byte[] bytes = d.
rawValue(bslen,
"Bitstream");
BitReader br =
new BitReader
(bytes
);
boolean xneg =
false;
boolean xsame = br.
get1();
if (xsame
) {
xneg = br.
get1();
} else
xbase++
;
boolean ysame = br.
get1();
boolean yneg =
false;
if (ysame
) {
yneg = br.
get1();
} else
ybase++
;
d.
item().
addText("xsame %b, xneg %b", xsame, xneg
);
d.
item().
addText("ysame %b, yneg %b", ysame, yneg
);
d.
item().
addText("xbase %d, ybase %d", xbase, ybase
);
if (extra
) {
boolean firstextra = br.
get1();
d.
item().
addText("first extra bit %b", firstextra
);
}
while (br.
getBitPosition() <=
8* bslen -
((extra
? 1:
0) + xbase + ybase
)) {
br.
getBitPosition();
int dx
;
if (xsame
) {
dx = br.
get(xbase
);
if (xneg
)
dx = -dx
;
} else {
dx = br.
sget2(xbase
);
}
int dy
;
if (ysame
) {
dy = br.
get(ybase
);
if (yneg
)
dy = -dy
;
} else {
dy = br.
sget2(ybase
);
}
currLat += dy
<< (24 - subdiv.
getBits());
currLon += dx
<< (24 - subdiv.
getBits());
Formatter fmt =
new Formatter();
fmt.
format("Coord %.5f,%.5f %d/%d", Utils.
toDegrees(currLat
), Utils.
toDegrees(currLon
), currLat, currLon
);
if (extra
) {
boolean isnode = br.
get1();
fmt.
format(", node=%b", isnode
);
}
d.
item().
addText(fmt.
toString());
}
int bleft =
8*bslen - br.
getBitPosition();
d.
item().
addText(bleft +
" bits left, " + br.
get(bleft
));
d.
gap();
}
d.
print(outStream
);
d.
setTitle(null);
}
private void displayPoints
(Displayer d, Subdiv subdiv,
int[] pointers,
int count
) {
d.
item().
addText("point start %x to %x", pointers
[count
], pointers
[count+
1]);
reader.
position(pointers
[count
]);
int num =
1;
while (reader.
position() < pointers
[count+
1]) {
d.
item().
addText("Point #%d", num++
);
d.
byteValue("Type %x");
int val = reader.
get3();
DisplayItem item = d.
item();
item.
setBytes3(val
);
boolean hasSubtype =
false;
if ((val
& 0x800000
) !=
0)
hasSubtype =
true;
boolean hasPoi =
false;
if ((val
& 0x400000
) !=
0)
hasPoi =
true;
val
&= 0x3fffff
;
if (hasPoi
)
item.
addText("Poi offset 0x%x", val
);
else
item.
addText("Label offset 0x%x (%s)", val, fetchLabel
(val
));
short dlon = d.
shortValue("Long delta %d");
short dlat = d.
shortValue("Lat delta %d");
double startLat = Utils.
toDegrees(fixDelta
(subdiv, subdiv.
getLatitude(), dlat
));
double startLon = Utils.
toDegrees(fixDelta
(subdiv, subdiv.
getLongitude(), dlon
));
d.
item().
addText("Start point %.5f,%.5f",
startLat,
startLon
);
if (hasSubtype
)
d.
byteValue("subtype %d");
d.
gap();
}
}
private int fixDelta
(Subdiv subdiv,
int base,
short dlat
) {
return base +
(dlat
<< (24 - subdiv.
getBits()));
}
private void readHeader
() {
int remain = getHeaderLen
() -
(int) reader.
position();
Displayer d =
new Displayer
(reader
);
d.
setTitle("RGN Header");
Section sect = readSection
(d,
"RGN 1",
1,
false,
false);
rgnStart =
(int) sect.
getStart();
int len = sect.
getLen();
d.
item().
addText("rgn end 0x%06x", rgnStart + len
);
remain -=
8;
if (getHeaderLen
() > 29) {
int rgn2 = d.
intValue("rgn2 %x");
len = d.
intValue("rgn2 size %d");
d.
item().
addText("rgn2 end 0x%06x", rgn2 + len
);
remain -=
8;
d.
rawValue(20);
remain -=
20;
int rgn3 = d.
intValue("rgn3 0x%06x");
len = d.
intValue("rgn3 size %d");
d.
item().
addText("rgn3 end 0x%06x", rgn3 + len
);
remain -=
8;
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
remain -=
20;
int rgn4 = d.
intValue("rgn4 0x%06x");
len = d.
intValue("rgn4 end %d");
d.
item().
addText("rgn4 end 0x%06x", rgn4 + len
);
remain -=
8;
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
d.
intValue("unknown %d");
remain -=
32;
}
assert remain ==
0 : remain
;
d.
rawValue(remain
);
d.
print(outStream
);
}
private void readLevel
(ImgFileReader treader
) {
treader.
position(levels.
getStart());
long end = levels.
getEnd();
int lowestLevel =
24;
while (treader.
position() < end
) {
int level = treader.
get();
int nbits = treader.
get();
int ndivs = treader.
getChar();
level
&= 0x7f
;
LevelInfo li =
new LevelInfo
(level, nbits
);
linfo
[level
] = li
;
Subdiv
[] divs =
new Subdiv
[ndivs
];
divinfo
[level
] = divs
;
lowestLevel = level
;
}
treader.
position(subdivs.
getStart());
int subdivNumber =
1;
int lastRgnOffset = treader.
get3();
for (int level =
23; level
>=
0; level--
) {
Subdiv
[] divs = divinfo
[level
];
if (divs ==
null)
continue;
int count = divs.
length;
while (count--
> 0) {
int elem = treader.
get();
int lon = treader.
get3();
int lat = treader.
get3();
treader.
getChar();
treader.
getChar();
if (level
> lowestLevel
)
treader.
getChar();
int endRgnOffset = treader.
getu3();
Subdiv subdiv =
new Subdiv
();
divs
[divs.
length - count -
1] = subdiv
;
subdiv.
setLevel(level
);
subdiv.
setNumber(subdivNumber++
);
subdiv.
setRgnOffset(lastRgnOffset
);
subdiv.
setRgnEnd(endRgnOffset
);
subdiv.
setBits(linfo
[level
].
getBits());
subdiv.
setLocation(lat, lon
);
subdiv.
setTypes(elem
);
lastRgnOffset = endRgnOffset
;
}
}
}
public static void main
(String[] args
) {
if (args.
length < 1) {
System.
err.
println("Usage: rgndisplay <filename>");
System.
exit(1);
}
String name = args
[0];
CommonDisplay nd =
new RgnDisplay
();
nd.
display(name,
"RGN");
}
}