1d9d4cf8b6
git-svn-id: https://osmand.googlecode.com/svn/trunk@839 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
346 lines
13 KiB
Java
346 lines
13 KiB
Java
package net.osmand.binary;
|
|
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.RandomAccessFile;
|
|
import java.text.MessageFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import net.osmand.binary.BinaryMapAddressReaderAdapter.AddressRegion;
|
|
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
|
|
import net.osmand.binary.BinaryMapIndexReader.MapRoot;
|
|
import net.osmand.binary.BinaryMapTransportReaderAdapter.TransportIndex;
|
|
import net.osmand.osm.MapUtils;
|
|
|
|
import com.google.protobuf.CodedOutputStream;
|
|
import com.google.protobuf.WireFormat;
|
|
|
|
public class BinaryInspector {
|
|
|
|
|
|
public static final int BUFFER_SIZE = 1 << 20;
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
inspector(args);
|
|
// test cases show info
|
|
// inspector(new String[]{"E:\\Information\\OSM maps\\osmand\\Minsk.obf"});
|
|
// inspector(new String[]{"E:\\Information\\OSM maps\\osmand\\Belarus_4.obf"});
|
|
// inspector(new String[]{"E:\\Information\\OSM maps\\osmand\\Belarus.obf"});
|
|
// inspector(new String[]{"E:\\Information\\OSM maps\\osm_map\\Poland.obf"});
|
|
// inspector(new String[]{"E:\\Information\\OSM maps\\osm_map\\Netherlands\\Netherlands_trans.map.obf"});
|
|
|
|
// test case extract parts
|
|
// inspector(new String[]{"-c", "E:\\Information\\OSM maps\\osmand\\Netherlands-addr-trans.map.obf",
|
|
// "E:\\Information\\OSM maps\\osmand\\Netherlands.map.obf", "-1"});
|
|
|
|
// test case
|
|
// inspector(new String[]{"-c", "E:\\Information\\OSM maps\\osmand\\Netherlands-addr-trans.map.obf",
|
|
// "E:\\Information\\OSM maps\\osmand\\Netherlands.map.obf", "-1",
|
|
// "E:\\Information\\OSM maps\\osmand\\Belarus_4.map.obf", "E:\\Information\\OSM maps\\osmand\\Minsk.map.obf"});
|
|
// inspector(new String[]{"E:\\Information\\OSM maps\\osmand\\Netherlands-addr-trans.map.obf"});
|
|
}
|
|
|
|
|
|
public static void inspector(String[] args) throws IOException {
|
|
if(args == null || args.length == 0){
|
|
printUsage(null);
|
|
return;
|
|
}
|
|
String f = args[0];
|
|
if(f.charAt(0) == '-'){
|
|
// command
|
|
if(f.equals("-c") || f.equals("-combine")) {
|
|
if(args.length < 4){
|
|
printUsage("Too few parameters to extract (require minimum 4)");
|
|
} else {
|
|
Map<File, String> parts = new LinkedHashMap<File, String>();
|
|
for (int i = 2; i < args.length; i++) {
|
|
File file = new File(args[i]);
|
|
if (!file.exists()) {
|
|
System.err.println("File to extract from doesn't exist " + args[i]);
|
|
return;
|
|
}
|
|
parts.put(file, null);
|
|
if(i < args.length - 1){
|
|
if(args[i+1].startsWith("-") || args[i+1].startsWith("+")){
|
|
parts.put(file, args[i+1]);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
List<Float> extracted = combineParts(new File(args[1]), parts);
|
|
if(extracted != null){
|
|
System.out.println("\n"+extracted.size()+" parts were successfully extracted to " + args[1]);
|
|
}
|
|
}
|
|
} else {
|
|
printUsage("Unknown command : "+ f);
|
|
}
|
|
} else {
|
|
File file = new File(f);
|
|
if(!file.exists()){
|
|
System.out.println("Binary OsmAnd index " + f + " was not found.");
|
|
return;
|
|
}
|
|
printFileInformation(file);
|
|
}
|
|
}
|
|
public static final void writeInt(CodedOutputStream ous, int v) throws IOException {
|
|
ous.writeRawByte((v >>> 24) & 0xFF);
|
|
ous.writeRawByte((v >>> 16) & 0xFF);
|
|
ous.writeRawByte((v >>> 8) & 0xFF);
|
|
ous.writeRawByte((v >>> 0) & 0xFF);
|
|
//written += 4;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static List<Float> combineParts(File fileToExtract, Map<File, String> partsToExtractFrom) throws IOException {
|
|
BinaryMapIndexReader[] indexes = new BinaryMapIndexReader[partsToExtractFrom.size()];
|
|
RandomAccessFile[] rafs = new RandomAccessFile[partsToExtractFrom.size()];
|
|
|
|
LinkedHashSet<Float>[] partsSet = new LinkedHashSet[partsToExtractFrom.size()];
|
|
int c = 0;
|
|
Set<String> addressNames = new LinkedHashSet<String>();
|
|
|
|
|
|
int version = -1;
|
|
// Go through all files and validate conistency
|
|
for(File f : partsToExtractFrom.keySet()){
|
|
if(f.getAbsolutePath().equals(fileToExtract.getAbsolutePath())){
|
|
System.err.println("Error : Input file is equal to output file " + f.getAbsolutePath());
|
|
return null;
|
|
}
|
|
rafs[c] = new RandomAccessFile(f, "r");
|
|
indexes[c] = new BinaryMapIndexReader(rafs[c]);
|
|
partsSet[c] = new LinkedHashSet<Float>();
|
|
if(version == -1){
|
|
version = indexes[c].getVersion();
|
|
} else {
|
|
if(indexes[c].getVersion() != version){
|
|
System.err.println("Error : Different input files has different input versions " + indexes[c].getVersion() + " != " + version);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
LinkedHashSet<Float> temp = new LinkedHashSet<Float>();
|
|
String pattern = partsToExtractFrom.get(f);
|
|
boolean minus = true;
|
|
for (int i = 0; i < indexes[c].getIndexes().size(); i++) {
|
|
partsSet[c].add(i + 1f);
|
|
BinaryIndexPart part = indexes[c].getIndexes().get(i);
|
|
if(part instanceof MapIndex){
|
|
List<MapRoot> roots = ((MapIndex) part).getRoots();
|
|
for(int j=0; j<roots.size(); j++){
|
|
partsSet[c].add((i+1f)+(j+1)/10f);
|
|
}
|
|
}
|
|
}
|
|
if(pattern != null){
|
|
minus = pattern.startsWith("-");
|
|
String[] split = pattern.substring(1).split(",");
|
|
for(String s : split){
|
|
temp.add(Float.parseFloat(s));
|
|
}
|
|
}
|
|
|
|
|
|
if(minus){
|
|
partsSet[c].removeAll(temp);
|
|
} else {
|
|
partsSet[c].retainAll(temp);
|
|
}
|
|
|
|
c++;
|
|
}
|
|
|
|
// write files
|
|
FileOutputStream fout = new FileOutputStream(fileToExtract);
|
|
CodedOutputStream ous = CodedOutputStream.newInstance(fout, BUFFER_SIZE);
|
|
List<Float> list = new ArrayList<Float>();
|
|
byte[] BUFFER_TO_READ = new byte[BUFFER_SIZE];
|
|
|
|
ous.writeInt32(OsmandOdb.OsmAndStructure.VERSION_FIELD_NUMBER, version);
|
|
|
|
|
|
for (int k = 0; k < indexes.length; k++) {
|
|
LinkedHashSet<Float> partSet = partsSet[k];
|
|
BinaryMapIndexReader index = indexes[k];
|
|
RandomAccessFile raf = rafs[k];
|
|
for (int i = 0; i < index.getIndexes().size(); i++) {
|
|
if (!partSet.contains(i + 1f)) {
|
|
continue;
|
|
}
|
|
list.add(i + 1f);
|
|
|
|
BinaryIndexPart part = index.getIndexes().get(i);
|
|
String map;
|
|
if (part instanceof MapIndex) {
|
|
ous.writeTag(OsmandOdb.OsmAndStructure.MAPINDEX_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
|
|
map = "Map";
|
|
List<MapRoot> roots = ((MapIndex) part).getRoots();
|
|
List<MapRoot> toSkip = new ArrayList<MapRoot>();
|
|
int newL = 0;
|
|
int tagAndFieldSize = CodedOutputStream.computeTagSize(OsmandOdb.OsmAndMapIndex.LEVELS_FIELD_NUMBER) + 4;
|
|
for(int j=0; j<roots.size(); j++){
|
|
if (!partSet.contains(i + 1f + (j+1)*0.1f)) {
|
|
newL -= (roots.get(j).getLength() + tagAndFieldSize);
|
|
toSkip.add(roots.get(j));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
writeInt(ous, part.getLength() + newL);
|
|
long seek = part.getFilePointer();
|
|
while(seek < (part.getFilePointer()+ part.getLength())){
|
|
MapRoot next = null;
|
|
for(MapRoot r : toSkip){
|
|
if(seek < r.getFilePointer()) {
|
|
if(next == null || next.getFilePointer() > r.getFilePointer()){
|
|
next = r;
|
|
}
|
|
}
|
|
|
|
}
|
|
if(next == null){
|
|
copyBinaryPart(ous, BUFFER_TO_READ, raf, seek, (int) (part.getLength() - (seek - part.getFilePointer())));
|
|
break;
|
|
} else {
|
|
int l = (int) (next.getFilePointer() - seek - tagAndFieldSize);
|
|
if(l > 0){
|
|
copyBinaryPart(ous, BUFFER_TO_READ, raf, seek, l);
|
|
}
|
|
seek += next.getLength() + tagAndFieldSize + l;
|
|
}
|
|
|
|
}
|
|
|
|
System.out.println(MessageFormat.format("{2} part {0} is extracted {1} bytes", part.getName(), part.getLength() + newL, map));
|
|
} else {
|
|
if (part instanceof AddressRegion) {
|
|
ous.writeTag(OsmandOdb.OsmAndStructure.ADDRESSINDEX_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
|
|
map = "Address";
|
|
if (addressNames.contains(part.getName())) {
|
|
System.err.println("Error : going to merge 2 addresses with same names. Skip " + part.getName());
|
|
continue;
|
|
}
|
|
addressNames.add(part.getName());
|
|
} else if (part instanceof TransportIndex) {
|
|
ous.writeTag(OsmandOdb.OsmAndStructure.TRANSPORTINDEX_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
|
|
map = "Transport";
|
|
} else {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
writeInt(ous, part.getLength());
|
|
copyBinaryPart(ous, BUFFER_TO_READ, raf, part.getFilePointer(), part.getLength());
|
|
System.out.println(MessageFormat.format("{2} part {0} is extracted {1} bytes", part.getName(), part.getLength(), map));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
ous.writeInt32(OsmandOdb.OsmAndStructure.VERSIONCONFIRM_FIELD_NUMBER, version);
|
|
ous.flush();
|
|
fout.close();
|
|
|
|
|
|
return list;
|
|
}
|
|
|
|
|
|
private static void copyBinaryPart(CodedOutputStream ous, byte[] BUFFER, RandomAccessFile raf, long fp, int length)
|
|
throws IOException {
|
|
raf.seek(fp);
|
|
int toRead = length;
|
|
while (toRead > 0) {
|
|
int read = raf.read(BUFFER);
|
|
if (read == -1) {
|
|
throw new IllegalArgumentException("Unexpected end of file");
|
|
}
|
|
if (toRead < read) {
|
|
read = toRead;
|
|
}
|
|
ous.writeRawBytes(BUFFER, 0, read);
|
|
toRead -= read;
|
|
}
|
|
}
|
|
|
|
|
|
protected static String formatBounds(int left, int right, int top, int bottom){
|
|
double l = MapUtils.get31LongitudeX(left);
|
|
double r = MapUtils.get31LongitudeX(right);
|
|
double t = MapUtils.get31LatitudeY(top);
|
|
double b = MapUtils.get31LatitudeY(bottom);
|
|
MessageFormat format = new MessageFormat("(left top - right bottom) : {0}, {1} NE - {2}, {3} NE", Locale.US);
|
|
return format.format(new Object[]{l, t, r, b});
|
|
}
|
|
|
|
|
|
public static void printFileInformation(File file) throws IOException {
|
|
RandomAccessFile r = new RandomAccessFile(file.getAbsolutePath(), "r");
|
|
try {
|
|
BinaryMapIndexReader index = new BinaryMapIndexReader(r);
|
|
int i = 1;
|
|
System.out.println("Binary index " + file.getName() + " version = " + index.getVersion());
|
|
for(BinaryIndexPart p : index.getIndexes()){
|
|
String partname = "";
|
|
if(p instanceof MapIndex ){
|
|
partname = "Map";
|
|
} else if(p instanceof TransportIndex){
|
|
partname = "Transport";
|
|
} else if(p instanceof AddressRegion){
|
|
partname = "Address";
|
|
}
|
|
String name = p.getName() == null ? "" : p.getName();
|
|
System.out.println(MessageFormat.format("{0}. {1} data {3} - {2} bytes", i, partname, p.getLength(), name));
|
|
if(p instanceof TransportIndex){
|
|
TransportIndex ti = ((TransportIndex) p);
|
|
int sh = (31 - BinaryMapIndexReader.TRANSPORT_STOP_ZOOM);
|
|
System.out.println("\t Bounds " + formatBounds(ti.getLeft() << sh, ti.getRight() << sh,
|
|
ti.getTop() << sh, ti.getBottom() << sh));
|
|
} else if(p instanceof MapIndex){
|
|
MapIndex m = ((MapIndex) p);
|
|
int j = 1;
|
|
for(MapRoot mi : m.getRoots()){
|
|
System.out.println(MessageFormat.format("\t{4}.{5} Map level minZoom = {0}, maxZoom = {1}, size = {2} bytes \n\t\tBounds {3}",
|
|
mi.getMinZoom(), mi.getMaxZoom(), mi.getLength(),
|
|
formatBounds(mi.getLeft(), mi.getRight(), mi.getTop(), mi.getBottom()),
|
|
i, j++));
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
|
|
} catch (IOException e) {
|
|
System.err.println("File is not valid index : " + file.getAbsolutePath());
|
|
throw e;
|
|
}
|
|
|
|
}
|
|
|
|
public static void printUsage(String warning) {
|
|
if(warning != null){
|
|
System.out.println(warning);
|
|
}
|
|
System.out.println("Inspector is console utility for working with binary indexes of OsmAnd.");
|
|
System.out.println("It allows print info about file, extract parts and merge indexes.");
|
|
System.out.println("\nUsage for print info : inspector [file]");
|
|
System.out.println(" Prints information about [file] binary index of OsmAnd.");
|
|
System.out.println("\nUsage for combining indexes : inspector -c file_to_create (file_from_extract ((+|-)parts_to_extract)? )*");
|
|
System.out.println("\tCreate new file of extracted parts from input file. [parts_to_extract] could be parts to include or exclude.");
|
|
System.out.println(" Example : inspector -c output_file input_file +1,2,3\n\tExtracts 1, 2, 3 parts (could be find in print info)");
|
|
System.out.println(" Example : inspector -c output_file input_file -2,3\n\tExtracts all parts excluding 2, 3");
|
|
System.out.println(" Example : inspector -c output_file input_file1 input_file2 input_file3\n\tSimply combine 3 files");
|
|
System.out.println(" Example : inspector -c output_file input_file1 input_file2 -4\n\tCombine all parts of 1st file and all parts excluding 4th part of 2nd file");
|
|
|
|
}
|
|
|
|
}
|