Rev 371 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2014 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 3 or
* 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.
*/
package test.files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import uk.me.parabola.imgfmt.app.ImgFileReader;
import uk.me.parabola.imgfmt.app.Label;
import uk.me.parabola.imgfmt.app.lbl.City;
import uk.me.parabola.imgfmt.app.lbl.LBLFileReader;
import uk.me.parabola.imgfmt.app.lbl.Zip;
import uk.me.parabola.imgfmt.app.net.NETHeader;
import uk.me.parabola.imgfmt.app.net.RoadDef;
/**
* @author Steve Ratcliffe
*/
public class NetFile
{
private final NETHeader netHeader =
new NETHeader
();
private final ImgFileReader reader
;
private LBLFileReader labels
;
private List<City
> cities
;
private int citySize
;
private List<Zip
> zips
;
private int zipSize
;
private final Map<Integer, RoadData
> roadCache =
new HashMap<>();
public NetFile
(ImgFileReader reader
) {
this.
reader = reader
;
netHeader.
readHeader(reader
);
}
/**
* Get the list of roads from the net section.
* <p/>
* Saving the bare minimum that is needed, please improve.
*
* @return A list of RoadDefs. Note that currently not everything is
* populated in the road def so it can't be written out as is.
*/
public RoadData getRoad
(int offset
) {
RoadData road = roadCache.
get(offset
);
if (road
!=
null)
return road
;
road =
new RoadData
();
road.
setOffset(offset
);
int start = netHeader.
getRoadDefinitionsStart();
reader.
position(start + offset
);
readLabels
(road
);
byte netFlags = reader.
get();
road.
setLength(reader.
getu3());
int[] counts =
new int[24];
int maxLevel =
0;
while (maxLevel
< 24) {
int n = reader.
get();
counts
[maxLevel++
] =
(n
& 0x7f
);
if ((n
& 0x80
) !=
0)
break;
}
for (int level =
0; level
< maxLevel
; level++
) {
int c = counts
[level
];
for (int j =
0; j
< c
; j++
) {
int idx = reader.
get();
int div = reader.
getChar();
if (level ==
0) {
Segment seg =
new Segment();
seg.
setDiv(div
);
seg.
setIdx(idx
);
road.
addSegment(seg
);
}
}
}
if ((netFlags
& RoadDef.
NET_FLAG_ADDRINFO) !=
0) {
char flags2 = reader.
getChar();
int zipFlag =
(flags2
>> 10) & 0x3
;
int cityFlag =
(flags2
>> 12) & 0x3
;
int numberFlag =
(flags2
>> 14) & 0x3
;
road.
setZip(fetchZipCity
(reader, zipFlag, zips, zipSize
));
road.
setCity(fetchZipCity
(reader, cityFlag, cities, citySize
));
fetchNumber
(reader, numberFlag
);
}
if ((netFlags
& RoadDef.
NET_FLAG_NODINFO) !=
0) {
int nodFlags = reader.
get();
int nbytes = nodFlags
& 0x3
;
if (nbytes
> 0) {
int offsetNod2 = reader.
getUint(nbytes +
1);
road.
setOffsetNod2(offsetNod2
);
}
}
roadCache.
put(offset, road
);
return road
;
}
/**
* Fetch a zip or a city.
*
* @param <T> Can be city or zip.
* @return The found City or Zip.
*/
private <T
> T fetchZipCity
(ImgFileReader reader,
int flag,
List<T
> list,
int size
) {
T item =
null;
if (flag ==
2) {
// fetch city/zip index
int ind =
(size ==
2) ? reader.
getChar() :
(reader.
get() & 0xff
);
if (ind
!=
0)
item = list.
get(ind -
1);
} else if (flag ==
3) {
// there is no item
} else if (flag ==
0) {
// Skip over these
reader.
get(reader.
get() & 0xff
);
} else if (flag ==
1) {
// Skip over these
int n = reader.
getChar();
reader.
get(n
);
} else {
assert false :
"flag is " + flag
;
}
return item
;
}
/**
* Fetch a block of numbers.
*
* @param reader The reader.
* @param numberFlag The flag that says how the block is formatted.
*/
private void fetchNumber
(ImgFileReader reader,
int numberFlag
) {
int n =
0;
if (numberFlag ==
0) {
n = reader.
get() & 0xff
;
} else if (numberFlag ==
1) {
n = reader.
getChar();
} else if (numberFlag ==
3) {
// There is no block
return;
} else {
// Possible but don't know what to do in this context
assert false;
}
if (n
> 0)
reader.
get(n
);
}
private void readLabels
(RoadData road
) {
for (int i =
0; i
< 4; i++
) {
int lab = reader.
getu3();
assert labels
!=
null;
Label label = labels.
fetchLabel(lab
& 0x7fffff
);
road.
addLabel(label
);
if ((lab
& 0x800000
) !=
0)
break;
}
}
public void setLableFile
(LBLFileReader labels
) {
this.
labels = labels
;
cities = labels.
getCities();
citySize = cities.
size() > 255? 2:
1;
zips = labels.
getZips();
zipSize = zips.
size() > 255 ? 2 :
1;
}
}