/*
* 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.ByteArrayOutputStream;
import java.nio.BufferUnderflowException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import test.files.RoadData;
import test.util.BitReaderLR;
import uk.me.parabola.imgfmt.Utils;
import uk.me.parabola.imgfmt.app.BitReader;
import uk.me.parabola.imgfmt.app.trergn.Subdivision;
/**
* Standalone program to display the RGN file.
*
* @author Steve Ratcliffe
*/
public class RgnDisplay
extends CommonDisplay
{
private static final int FLAG_NETINFO = 0x800000
;
private static final int FLAG_EXTRA = 0x400000
;
private static final int MASK_LABEL = 0x3fffff
;
private static final int NUM_LINK_SIZES =
3;
private int rgnStart
;
List<HuffmanDecoder
> decoders =
new ArrayList<>();
private Section extPolygons
;
private Section extLines
;
private Section extPoints
;
private int polygonsGlbFlags
;
private int linesGlbFlags
;
private int pointsGlbFlags
;
private int[] polygonsLclFlags
;
private int[] linesLclFlags
;
private int[] pointsLclFlags
;
private Section rgn5
;
private HuffmanDecoder huffmanDecoder
;
private Map<Integer, HuffmanDecoder
> huffmanTables =
new HashMap<>();
@
Override
protected void print
() {
readCommonHeader
();
readHeader
();
if (rgn5
!=
null) {
// read and display Huffman table(s)
displayRgn5
();
}
openLbl
();
openNet
();
if (reader.
getGMPOffset() > 0)
openNod
();
readBody
();
}
private void readBody
() {
openTre
();
Displayer d =
new Displayer
(reader
);
d.
setTitle("RGN body");
d.
print(outStream
);
for (int i =
23; i
>=
0; i--
) {
Subdivision
[] divInfo = tre.
subdivForLevel(i
);
for (Subdivision sd : divInfo
)
printDiv
(sd
);
}
}
private static int numberOfPointers
(Subdivision sd
) {
int count =
0;
if (sd.
hasPoints()) count++
;
if (sd.
hasIndPoints()) count++
;
if (sd.
hasPolylines()) count++
;
if (sd.
hasPolygons()) count++
;
if (sd.
hasRoadRefs()) count++
;
if (count
> 0)
count--
;
return count
;
}
/**
* 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
(Subdivision subdiv
) {
Displayer d =
new Displayer
(reader
);
d.
setTitle("Level " + subdiv.
getZoom().
getLevel() +
", Subdiv " + subdiv.
getNumber());
int offset = subdiv.
getStartRgnPointer();
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 = numberOfPointers
(subdiv
);
int[] pointers =
new int[n +
2];
pointers
[0] = rgnStart + offset +
(2 * n
);
for (int i =
0; i
< n
; i++
) {
pointers
[i +
1] = rgnStart + offset + d.
charValue("Pointer 0x%x");
}
pointers
[n +
1] = rgnStart + subdiv.
getEndRgnPointer();
d.
item().
addText("final at %x, (end %x)", pointers
[n +
1], subdiv.
getEndRgnPointer());
int count =
0;
if (subdiv.
hasPoints()) {
displayPoints
(d, subdiv, pointers, count
);
count++
;
}
if (subdiv.
hasIndPoints()) {
displayPoints
(d, subdiv, pointers, count
);
count++
;
}
if (subdiv.
hasPolylines()) {
displayLines
(d, subdiv, pointers, count,
"Line");
count++
;
}
if (subdiv.
hasPolygons()) {
displayLines
(d, subdiv, pointers, count,
"Polygon");
count++
;
}
if (subdiv.
hasRoadRefs()) {
displayRoadRefs
(d, subdiv, pointers, count,
"RoadRef");
}
if (subdiv.
getExtTypeAreasSize() > 0) {
long start = extPolygons.
getStart() + subdiv.
getExtTypeAreasOffset();
long end = start + subdiv.
getExtTypeAreasSize();
displayExtLines
(d, subdiv,
"ext-polygon", start, end
);
}
if (subdiv.
getExtTypeLinesSize() > 0) {
long start = extLines.
getStart() + subdiv.
getExtTypeLinesOffset();
long end = start + subdiv.
getExtTypeLinesSize();
displayExtLines
(d, subdiv,
"ext-line", start, end
);
}
if (subdiv.
getExtTypePointsSize() > 0) {
displayExtPoints
(d, subdiv
);
}
d.
print(outStream
);
}
private void displayRoadRefs
(Displayer d, Subdivision subdiv,
int[] pointers,
int count,
String kind
) {
d.
item().
addText("%s start %x to %x", kind.
toLowerCase(), pointers
[count
], pointers
[count +
1]);
reader.
position(pointers
[count
]);
if (nod ==
null)
d.
rawValue((int) (pointers
[count +
1] - reader.
position()),
"???");
int roadNo =
0;
while (reader.
position() < pointers
[count +
1]) {
AtomicInteger varLength =
new AtomicInteger();
roadNo++
;
int size = d.
varUInt32("size %d", varLength
);
long pos = reader.
position();
DisplayItem item = d.
byteItem();
int flags = item.
getValue();
int numBits =
0;
int[] bits =
new int[NUM_LINK_SIZES
];
for (int i =
0; i
< NUM_LINK_SIZES
; i++
) {
switch (flags
>> (2 * i
) & 0x3
) {
case 1:
bits
[i
] =
4;
break;
case 2:
bits
[i
] =
8;
break;
case 3:
bits
[i
] =
10;
break;
default:
}
numBits += bits
[i
];
}
item.
addText("road %d flags=0x%x -> %d+%d+%d bits", roadNo, flags, bits
[0], bits
[1], bits
[2]);
int blockIndexId = d.
intValue(nod.
getIndexIdSize(),
"NOD-blockIndexId %d");
item = d.
rawItem((numBits +
7) /
8);
BitReader br =
new BitReader
(item.
getBytes());
int numb8 = bits
[0] ==
0 ? 0 : br.
get(bits
[0]) +
1;
int numb10 = bits
[1] ==
0 ? 0 : br.
get(bits
[1]) +
1;
int numb16 = bits
[2] ==
0 ? 0 : br.
get(bits
[2]) +
1;
int countData = item.
getValue();
item.
addText("counter data 0x%x -> %d x 8-bit, %d x 10-bit, %d x 16-bit entries", countData, numb8, numb10,
numb16
);
int linkId
;
int lineId
;
// read the items, first come 8-bit entries, then 16-bit entries, finally the 10
// bit entries
int numIds = numb8 + numb10 + numb16
;
int shift =
0;
for (int i =
0; i
< numIds
; i++
) {
long posIds = reader.
position();
if (i
< numb8
) {
item = d.
byteItem();
linkId = item.
getValue();
lineId =
0;
} else {
int v16 = reader.
get2u();
if (i
>= numb8 + numb16
) {
linkId =
(v16
>> shift
) & 0xff
;
lineId =
((v16
>> (shift +
8)) & 0x3
) +
1;
if (shift
< 6 && i
< numIds -
1)
reader.
position(reader.
position() -
1); // reuse for next
shift +=
2;
shift
&=
7;
} else {
linkId = v16
& 0xff
;
lineId = v16
>> 8;
assert lineId
> 4; // else a 10 bit entry would be enough
}
int bytesForData =
(int) (reader.
position() - posIds
);
reader.
position(posIds
);
item = d.
rawItem(bytesForData
);
}
item.
addText("linkId = %d, lineId = %d", linkId, lineId
);
// TODO:
// blockInfo = nod.getBlockInfo(blockIndexId);
// net->link(subdiv, shift, netHdl, nod, nodHdl, nodHdl2, lbl, lblHdl,
// blockInfo, linkId, lineId, lines);
}
assert reader.
position() - pos == size
;
}
d.
rawValue((int) (pointers
[count +
1] - reader.
position()),
"???");
d.
print(outStream
);
d.
setTitle(null);
}
private void displayLines
(Displayer d, Subdivision subdiv,
int[] pointers,
int count,
String kind
) {
d.
item().
addText("%s start %x to %x", kind.
toLowerCase(), 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.
setBytes1(reader.
get1u());
item.
addText("%s %d", kind, lineNo++
);
if ("Line".
equals(kind
)) {
item.
addText("Type 0x%x %sdirection", type
& 0x3f,
(type
& 0x40
) !=
0 ? "has" :
"no ");
} else
item.
addText("Type 0x%x", type
& 0x7f
);
boolean twoByteBitLength =
false;
if ((type
& 0x80
) !=
0)
twoByteBitLength =
true;
item = d.
item();
int labval = reader.
get3u();
item.
setBytes3(labval
);
int off = labval
& MASK_LABEL
;
boolean extra =
(labval
& FLAG_EXTRA
) !=
0;
boolean netinfo =
(labval
& FLAG_NETINFO
) !=
0;
if (netinfo
) {
String name =
"invalid";
RoadData road = net.
getRoad(off
);
if (road
!=
null) {
name = road.
getLabel(0).
getText();
}
item.
addText("NET offset: 0x%06x (%s)", off, name
);
} 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 %d/%d", Utils.
toDegrees(currLat
), Utils.
toDegrees(currLon
), currLat,
currLon
);
int bslen = twoByteBitLength
? d.
charValue("Bitstream length (2 byte) %d")
: d.
byteValue("Bitstream length %d") & 0xff
;
displayBitStream
(d, bslen +
1, subdiv.
getShift(), kind, extra, currLat, currLon
);
d.
gap();
d.
print(outStream
);
d.
setTitle(null);
}
d.
print(outStream
);
d.
setTitle(null);
}
private void displayPoints
(Displayer d, Subdivision 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.
get3u();
DisplayItem item = d.
item();
item.
setBytes3(val
);
boolean hasSubtype =
(val
& 0x800000
) !=
0;
boolean hasPoi =
(val
& 0x400000
) !=
0;
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();
}
d.
print(outStream
);
d.
setTitle(null);
}
void displayExtraBytes
(Displayer d
) {
ByteArrayOutputStream bytes =
new ByteArrayOutputStream();
byte b1 = reader.
get();
bytes.
write(b1
);
if ((b1
& 0xe0
) !=
0) {
// varying length, search for 0x01 as this seems to be the terminator
do {
b1 = reader.
get();
bytes.
write(b1
);
} while (b1
!= 0x01
);
} else if ((b1
& 0xa0
) !=
0) {
bytes.
write(reader.
get());
bytes.
write(reader.
get());
} else if ((b1
& 0x80
) !=
0) {
bytes.
write(reader.
get());
}
DisplayItem item = d.
item();
item.
setBytes(bytes.
toByteArray());
item.
addText("extra bytes");
}
private void displayExtPoints
(Displayer d, Subdivision subdiv
) {
long start = extPoints.
getStart() + subdiv.
getExtTypePointsOffset();
long end = start + subdiv.
getExtTypePointsSize();
reader.
position(start
);
d.
item().
addText("ext-point start %x to %x", start, end
);
int num =
1;
while (reader.
position() < end
) {
d.
item().
addText("Ext-Point #%d", num++
);
DisplayItem item = d.
charItem();
int typeData = item.
getValue();
int type =
(typeData
& 0xff
) << 8;
int b1 =
(typeData
>> 8) & 0xff
;
boolean hasExtra =
(b1
& 0x80
) !=
0;
boolean hasLcl =
(b1
& 0x40
) !=
0;
boolean hasLabel =
(b1
& 0x20
) !=
0;
type |= 0x10000 +
(b1
& 0x1f
);
item.
addText("Type %x hasExtra=%b hasLcl=%b", type, hasExtra, hasLcl
);
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 (hasLabel
) {
int val = reader.
get3u();
boolean hasPoi =
(val
& 0x400000
) !=
0;
item = d.
item();
item.
setBytes3(val
);
val
&= 0x3fffff
;
if (hasPoi
) {
item.
addText("Poi offset 0x%x", val
);
} else
item.
addText("Label offset 0x%x (%s)", val, fetchLabel
(val
));
}
if (hasExtra
) {
displayClassFields
(d,
"ext-point");
}
if (hasLcl
) {
skipLclFields
(d, pointsLclFlags
);
}
if (pointsGlbFlags
!=
0)
skipGblFields
(d, pointsGlbFlags
);
d.
gap();
}
d.
print(outStream
);
d.
setTitle(null);
}
private void skipLclFields
(Displayer d,
int[] flags
) {
if (flags
[0] ==
0)
return;
int mask = 0xFFFFFFFF
;
if ((flags
[0] & 0x20000000
) !=
0) {
long pos = reader.
position();
mask = readVBitMask
();
int len =
(int) (reader.
position() - pos
);
reader.
position(pos
);
DisplayItem item = d.
rawItem(len
);
item.
addText(String.
format("var length mask 0x%x", mask
));
}
int j =
0;
for (int i =
0; i
< 29; i++
) {
if (((flags
[0] >> i
) & 0x1
) !=
0) {
if ((mask
& 0x1
) !=
0) {
int m = flags
[(j
>> 4) +
1] >> ((j
* 2) & 0x1e
) & 3;
int skip =
0;
if (m ==
3) {
AtomicInteger varLength =
new AtomicInteger();
skip = d.
varLength("Lcl length %d", varLength
);
} else
skip = m +
1;
d.
rawValue(skip,
"Lcl data ???");
}
mask
>>=
1;
if (mask ==
0)
break;
j++
;
}
}
d.
print(outStream
);
d.
setTitle(null);
}
/**
* Read a bit mask stored with varying number of bytes.
* @return an int containing the mask
*/
private int readVBitMask
() {
int peek = reader.
get1u();
int mask
;
if ((peek
& 0x1
) !=
0)
return (peek
>> 1);
reader.
position(reader.
position() -
1);
if ((peek
& 0x2
) !=
0) {
mask = reader.
get2u();
return mask
>> 2;
}
if ((peek
& 0x4
) !=
0) {
mask = reader.
get3u();
} else {
mask = reader.
get4();
}
return mask
>> 3;
}
public static double toDegrees32
(long val
) {
return ((double) val /
(double) (1l
<< 31)) * 180.0;
}
private void displayExtLines
(Displayer d, Subdivision subdiv,
String kind,
long start,
long end
) {
reader.
position(start
);
int num =
0;
d.
item().
addText("%s start %x to %x", kind.
toLowerCase(), start, end
);
boolean isLine =
"ext-line".
equals(kind
);
Section section = isLine
? extLines : extPolygons
;
int extraShift = subdiv.
getZoom().
getLevel() ==
0 ? (tre.
getTre7Magic() >> 11) & 0x7 :
0;
final long baseLat32 =
((long) subdiv.
getLatitude()) << 8;
final long baseLon32 =
((long) subdiv.
getLongitude()) << 8;
while (reader.
position() < end
) {
d.
item().
addText("%s %d", kind, ++num
);
DisplayItem item = d.
charItem();
int typeData = item.
getValue();
int type =
(typeData
& 0xff
) << 8;
int b1 =
(typeData
>> 8) & 0xff
;
boolean hasExtra =
(b1
& 0x80
) !=
0;
boolean hasLcl =
(b1
& 0x40
) !=
0;
boolean hasLabel =
(b1
& 0x20
) !=
0;
type |= 0x10000 +
(b1
& 0x1f
);
item.
addText("Type %x hasExtra=%b hasLcl=%b", type, hasExtra, hasLcl
);
int dlon = d.
shortValue("Long delta %d");
int dlat = d.
shortValue("Lat delta %d");
AtomicInteger varLength =
new AtomicInteger();
int bslen = d.
varLength("Bitstream length %d", varLength
);
if (reader.
position() + bslen
> section.
getEnd()) {
d.
item().
addText("bitstream length too high?");
break;
}
if (huffmanDecoder
!=
null) {
long lat32 = baseLat32 +
(dlat
<< 32 - subdiv.
getResolution());
long lon32 = baseLon32 +
(dlon
<< 32 - subdiv.
getResolution());
int dx
;
int dy
;
long bspos = reader.
position();
d.
rawValue(bslen,
"Huffman encoded delta stream");
assert reader.
position() == bspos + bslen
;
reader.
position(bspos
);
BitReaderLR br =
new BitReaderLR
(reader, bslen
);
int xSign =
0;
int ySign =
0;
if (isLine
) {
boolean xsame = br.
get1() ==
0;
boolean xneg =
false;
if (!xsame
) {
xneg = br.
get1() !=
0;
xSign = xneg
? -
1 :
1;
}
boolean ysame = br.
get1() ==
0;
boolean yneg =
false;
if (!ysame
) {
yneg = br.
get1() !=
0;
ySign = yneg
? -
1 :
1;
}
d.
item().
addText("xsame %b, xneg %b", xsame, xneg
);
d.
item().
addText("ysame %b, yneg %b", ysame, yneg
);
}
int extra = br.
get1(); // always 0?
if (extra
!=
0)
assert extra ==
0;
if (extraShift
!=
0) {
dx = readOffset
(br
);
dy = readOffset
(br
);
lon32 |= dx
<< (32 - subdiv.
getResolution() - extraShift
);
lat32 |= dy
<< (32 - subdiv.
getResolution() - extraShift
);
}
d.
item().
addText("Start point %.6f,%.6f", toDegrees32
(lat32
), toDegrees32
(lon32
));
while (br.
hasRemaining()) {
try {
dx = readDelta
(br, xSign
);
dy = readDelta
(br, ySign
);
} catch (BufferUnderflowException e
) {
break;
}
lon32 += dx
<< (32 - subdiv.
getResolution() - extraShift
);
if (lon32
< 0 && subdiv.
getLongitude() >=
0)
lon32 = 0x7fffffff
;
lat32 += dy
<< (32 - subdiv.
getResolution() - extraShift
);
d.
item().
addText("Coord %.6f,%.6f [%+d,%+d]", toDegrees32
(lat32
), toDegrees32
(lon32
), dx, dy
);
d.
print(outStream
);
d.
setTitle(null);
}
reader.
position(bspos + bslen
);
} else {
int currLat = fixDelta
(subdiv, subdiv.
getLatitude(), dlat
);
int currLon = fixDelta
(subdiv, subdiv.
getLongitude(), dlon
);
d.
item().
addText("Start point %.5f,%.5f %d/%d", Utils.
toDegrees(currLat
), Utils.
toDegrees(currLon
), currLat,
currLon
);
displayBitStream
(d, bslen, subdiv.
getShift(), kind,
false /* no extra */, currLat, currLon
);
}
if (hasLabel
){
item = d.
item();
int labval = reader.
get3u();
item.
setBytes3(labval
);
int off = labval
& MASK_LABEL
;
item.
addText("Label offset: 0x%06x (%s)", off, fetchLabel
(off
));
}
if (hasExtra
){
displayClassFields
(d, kind
);
}
if (hasLcl
) {
skipLclFields
(d, isLine
? linesLclFlags : polygonsLclFlags
);
}
int gblFlags = isLine
? linesGlbFlags : polygonsGlbFlags
;
if (gblFlags
!=
0)
skipGblFields
(d, gblFlags
);
d.
gap();
}
d.
print(outStream
);
d.
setTitle(null);
}
private int readDelta
(BitReaderLR br,
int sign
) {
int symbol = huffmanDecoder.
readSymbol(br
);
if (symbol
!=
0 && sign ==
0) {
int bit = br.
get1();
sign = bit ==
1 ? -
1 :
1;
}
return sign
* symbol
;
}
private int readOffset
(BitReaderLR br
) {
return readDelta
(br,
1);
}
private static void skipGblFields
(Displayer d,
int flags
) {
int cnt =
0;
do {
cnt = cnt +
(flags
& 3);
flags = flags
>> 2;
} while (flags
!=
0);
d.
rawValue(cnt,
"gbl data");
}
private void displayClassFields
(Displayer d,
String kind
) {
byte b1 = d.
byteValue("class field flag?");
final int rs
;
switch ((b1
& 0xff
) >> 5) {
case 4:
rs =
1;
break;
case 5:
rs =
2;
break;
case 6:
rs =
3;
break;
case 7:
AtomicInteger varLength =
new AtomicInteger();
rs = reader.
readVarLength(varLength
);
break;
default:
rs =
0;
break;
}
if (rs
!=
0) {
d.
rawValue(rs,
"class fields data");
}
}
private static boolean displayBitStream
(Displayer d,
final int bslen,
final int shift,
final String kind,
final boolean extra,
final int _currLat,
final int _currLon
) {
int base = d.
byteValue("Base %x");
byte[] bytes = d.
rawValue(bslen -
1,
"Bitstream");
BitReader br =
new BitReader
(bytes
);
int currLat = _currLat
;
int currLon = _currLon
;
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 (br.
getNumberOfBits() ==
0) {
d.
item().
addText("bitstream is empty!");
d.
gap();
return false;
}
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
);
}
if (kind.
startsWith("ext-")) {
br.
get1();
}
int needed = xbase + ybase +
(extra
? 1 :
0);
int lastUsedPos = br.
getBitPosition();
while (needed
<= br.
getNumberOfBits() - br.
getBitPosition()) {
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
);
}
boolean isnode = extra
&& br.
get1();
if (!isnode
&& dx ==
0 && dy ==
0 && br.
getNumberOfBits() - br.
getBitPosition() < 8 + needed
)
continue;
lastUsedPos = br.
getBitPosition();
currLat += dy
<< shift
;
currLon += dx
<< shift
;
double latDeg = Utils.
toDegrees(currLat
);
double lonDeg = Utils.
toDegrees(currLon
);
assert latDeg
>= -
90 && latDeg
<=
90 :
"invalid lat in bitstream";
assert lonDeg
>= -
180 && latDeg
<=
180 :
"invalid lon in bitstream";
String extraInf = extra
? String.
format(", node=%b", isnode
) :
"";
d.
item().
addText(String.
format(Locale.
ENGLISH,
"Coord %.5f,%.5f %d/%d%s [%+d,%+d]",
latDeg, lonDeg, currLat, currLon, extraInf, dx,dy
));
}
int bleft = br.
getNumberOfBits() - br.
getBitPosition();
d.
item().
addText((bleft + br.
getBitPosition() - lastUsedPos
) +
" bits left, " + br.
get(bleft
));
return true;
}
private static int fixDelta
(Subdivision subdiv,
int base,
int dlat
) {
return base +
(dlat
<< subdiv.
getShift());
}
private void readHeader
() {
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
);
if (getHeaderLen
() > 29) {
extPolygons = readSection
(d,
"RGN 2 (extended polygons)",
2,
false,
true);
polygonsGlbFlags = d.
intValue("polygons Glb Flags %x");
polygonsLclFlags =
new int[3];
polygonsLclFlags
[0] = d.
intValue("polygonsLclFlags[0] %x");
polygonsLclFlags
[1] = d.
intValue("polygonsLclFlags[1] %x");
polygonsLclFlags
[2] = d.
intValue("polygonsLclFlags[2] %x");
extLines = readSection
(d,
"RGN 3 (extended lines)",
3,
false,
true);
linesGlbFlags = d.
intValue("lines Glb Flags %x");
linesLclFlags =
new int[3];
linesLclFlags
[0] = d.
intValue("linesLclFlags[0] %x");
linesLclFlags
[1] = d.
intValue("linesLclFlags[1] %x");
linesLclFlags
[2] = d.
intValue("linesLclFlags[2] %x");
extPoints = readSection
(d,
"RGN 4 (extended points)",
4,
false,
true);
pointsGlbFlags = d.
intValue("points Glb Flags %x");
pointsLclFlags =
new int[3];
pointsLclFlags
[0] = d.
intValue("pointsLclFlags[0] %x");
pointsLclFlags
[1] = d.
intValue("pointsLclFlags[1] %x");
pointsLclFlags
[2] = d.
intValue("pointsLclFlags[2] %x");
}
if (getHeaderLen
() > 101) {
rgn5 = readSection
(d,
"RGN 5",
5,
false,
true);
}
d.
rawValue((int) (getHeaderLen
() - reader.
position() + reader.
getGMPOffset()));
d.
print(outStream
);
}
private void displayRgn5
() {
int r5start =
(int) rgn5.
getStart();
int r5len = rgn5.
getLen();
if (r5len ==
0)
return;
Displayer d =
new Displayer
(reader
);
d.
setTitle("RGN5 (decompression codebook Huffman trees)");
reader.
position(r5start
);
while (reader.
position() < rgn5.
getEnd()) {
HuffmanDecoder decoder = readHuffmanTable
(d, reader.
position());
decoders.
add(decoder
);
}
d.
rawValue((int) (rgn5.
getEnd() - reader.
position()));
if ((rgn5.
getMagic() & 0x1e
) !=
0) {
int tableId =
((rgn5.
getMagic() >> 1) & 0xf
) -
1;
huffmanDecoder = decoders.
get(0);
huffmanTables.
put(tableId, huffmanDecoder
);
}
d.
print(outStream
);
}
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");
}
}