package net.osmand.binary; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import net.osmand.PlatformUtil; import net.osmand.binary.BinaryMapAddressReaderAdapter.AddressRegion; import net.osmand.binary.BinaryMapAddressReaderAdapter.CitiesBlock; import net.osmand.binary.BinaryMapIndexReader.MapIndex; import net.osmand.binary.BinaryMapIndexReader.MapRoot; import net.osmand.binary.BinaryMapPoiReaderAdapter.PoiRegion; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion; import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion; import net.osmand.binary.BinaryMapTransportReaderAdapter.IndexStringTable; import net.osmand.binary.BinaryMapTransportReaderAdapter.TransportIndex; import net.osmand.binary.OsmandIndex.AddressPart; import net.osmand.binary.OsmandIndex.CityBlock; import net.osmand.binary.OsmandIndex.FileIndex; import net.osmand.binary.OsmandIndex.MapLevel; import net.osmand.binary.OsmandIndex.MapPart; import net.osmand.binary.OsmandIndex.OsmAndStoredIndex; import net.osmand.binary.OsmandIndex.PoiPart; import net.osmand.binary.OsmandIndex.RoutingPart; import net.osmand.binary.OsmandIndex.RoutingSubregion; import net.osmand.binary.OsmandIndex.TransportPart; import net.osmand.util.MapUtils; import org.apache.commons.logging.Log; public class CachedOsmandIndexes { private OsmAndStoredIndex storedIndex; private OsmAndStoredIndex.Builder storedIndexBuilder; private Log log = PlatformUtil.getLog(CachedOsmandIndexes.class); private boolean hasChanged = true; public static final int VERSION = 2; public void addToCache(BinaryMapIndexReader reader, File f) { hasChanged = true; if(storedIndexBuilder == null) { storedIndexBuilder = OsmandIndex.OsmAndStoredIndex.newBuilder(); storedIndexBuilder.setVersion(VERSION); storedIndexBuilder.setDateCreated(System.currentTimeMillis()); if(storedIndex != null) { for(FileIndex ex : storedIndex.getFileIndexList()) { storedIndexBuilder.addFileIndex(ex); } } } FileIndex.Builder fileIndex = OsmandIndex.FileIndex.newBuilder(); long d = reader.getDateCreated(); fileIndex.setDateModified(d== 0?f.lastModified() : d); fileIndex.setSize(f.length()); fileIndex.setVersion(reader.getVersion()); fileIndex.setFileName(f.getName()); for(MapIndex index : reader.getMapIndexes()) { MapPart.Builder map = OsmandIndex.MapPart.newBuilder(); map.setSize(index.getLength()); map.setOffset(index.getFilePointer()); if(index.getName() != null) { map.setName(index.getName()); } for(MapRoot mr : index.getRoots() ) { MapLevel.Builder lev = OsmandIndex.MapLevel.newBuilder(); lev.setSize(mr.length); lev.setOffset(mr.filePointer); lev.setLeft(mr.left); lev.setRight(mr.right); lev.setTop(mr.top); lev.setBottom(mr.bottom); lev.setMinzoom(mr.minZoom); lev.setMaxzoom(mr.maxZoom); map.addLevels(lev); } fileIndex.addMapIndex(map); } for(AddressRegion index : reader.getAddressIndexes()) { AddressPart.Builder addr = OsmandIndex.AddressPart.newBuilder(); addr.setSize(index.getLength()); addr.setOffset(index.getFilePointer()); if(index.getName() != null) { addr.setName(index.getName()); } if(index.getEnName() != null) { addr.setNameEn(index.getEnName()); } addr.setIndexNameOffset(index.getIndexNameOffset()); for(CitiesBlock mr : index.getCities() ) { CityBlock.Builder cblock = OsmandIndex.CityBlock.newBuilder(); cblock.setSize(mr.length); cblock.setOffset(mr.filePointer); cblock.setType(mr.type); addr.addCities(cblock); } for(String s : index.getAttributeTagsTable()) { addr.addAdditionalTags(s); } fileIndex.addAddressIndex(addr); } for(PoiRegion index : reader.getPoiIndexes()) { PoiPart.Builder poi = OsmandIndex.PoiPart.newBuilder(); poi.setSize(index.getLength()); poi.setOffset(index.getFilePointer()); if(index.getName() != null) { poi.setName(index.getName()); } poi.setLeft(index.left31); poi.setRight(index.right31); poi.setTop(index.top31); poi.setBottom(index.bottom31); fileIndex.addPoiIndex(poi.build()); } for(TransportIndex index : reader.getTransportIndexes()) { TransportPart.Builder transport = OsmandIndex.TransportPart.newBuilder(); transport.setSize(index.getLength()); transport.setOffset(index.getFilePointer()); if(index.getName() != null) { transport.setName(index.getName()); } transport.setLeft(index.getLeft()); transport.setRight(index.getRight()); transport.setTop(index.getTop()); transport.setBottom(index.getBottom()); transport.setStopsTableLength(index.stopsFileLength); transport.setStopsTableOffset(index.stopsFileOffset); transport.setStringTableLength(index.stringTable.length); transport.setStringTableOffset(index.stringTable.fileOffset); fileIndex.addTransportIndex(transport); } for(RouteRegion index : reader.getRoutingIndexes()) { RoutingPart.Builder routing = OsmandIndex.RoutingPart.newBuilder(); routing.setSize(index.getLength()); routing.setOffset(index.getFilePointer()); if(index.getName() != null) { routing.setName(index.getName()); } for(RouteSubregion sub : index.getSubregions()) { addRouteSubregion(routing, sub, false); } for(RouteSubregion sub : index.getBaseSubregions()) { addRouteSubregion(routing, sub, true); } fileIndex.addRoutingIndex(routing); } storedIndexBuilder.addFileIndex(fileIndex); } private void addRouteSubregion(RoutingPart.Builder routing, RouteSubregion sub, boolean base) { OsmandIndex.RoutingSubregion.Builder rpart = OsmandIndex.RoutingSubregion.newBuilder(); rpart.setSize(sub.length); rpart.setOffset(sub.filePointer); rpart.setLeft(sub.left); rpart.setRight(sub.right); rpart.setTop(sub.top); rpart.setBasemap(base); rpart.setBottom(sub.bottom); rpart.setShifToData(sub.shiftToData); routing.addSubregions(rpart); } public BinaryMapIndexReader getReader(File f) throws IOException { RandomAccessFile mf = new RandomAccessFile(f.getPath(), "r"); FileIndex found = null; if (storedIndex != null) { for (int i = 0; i < storedIndex.getFileIndexCount(); i++) { FileIndex fi = storedIndex.getFileIndex(i); if (f.length() == fi.getSize() && f.getName().equals(fi.getFileName())) { // f.lastModified() == fi.getDateModified() found = fi; break; } } } BinaryMapIndexReader reader = null; if (found == null) { long val = System.currentTimeMillis(); reader = new BinaryMapIndexReader(mf, f); addToCache(reader, f); if (log.isDebugEnabled()) { log.debug("Initializing db " + f.getAbsolutePath() + " " + (System.currentTimeMillis() - val ) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } else { reader = initFileIndex(found, mf, f); } return reader; } private BinaryMapIndexReader initFileIndex(FileIndex found, RandomAccessFile mf, File f) throws IOException { BinaryMapIndexReader reader = new BinaryMapIndexReader(mf, f, false); reader.version = found.getVersion(); reader.dateCreated = found.getDateModified(); for(MapPart index : found.getMapIndexList()) { MapIndex mi = new MapIndex(); mi.length = (int) index.getSize(); mi.filePointer = (int) index.getOffset(); mi.name = index.getName(); for(MapLevel mr : index.getLevelsList()) { MapRoot root = new MapRoot(); root.length = (int) mr.getSize(); root.filePointer = (int) mr.getOffset(); root.left = mr.getLeft(); root.right = mr.getRight(); root.top = mr.getTop(); root.bottom = mr.getBottom(); root.minZoom = mr.getMinzoom(); root.maxZoom = mr.getMaxzoom(); mi.roots.add(root); } reader.mapIndexes.add(mi); reader.indexes.add(mi); reader.basemap = reader.basemap || mi.isBaseMap(); } for(AddressPart index : found.getAddressIndexList()) { AddressRegion mi = new AddressRegion(); mi.length = (int) index.getSize(); mi.filePointer = (int) index.getOffset(); mi.name = index.getName(); mi.enName = index.getNameEn(); mi.indexNameOffset = index.getIndexNameOffset(); for(CityBlock mr : index.getCitiesList() ) { CitiesBlock cblock = new CitiesBlock(); cblock.length = (int) mr.getSize(); cblock.filePointer = (int) mr.getOffset(); cblock.type = mr.getType(); mi.cities.add(cblock); } for(String s : index.getAdditionalTagsList()) { mi.attributeTagsTable.add(s); } reader.addressIndexes.add(mi); reader.indexes.add(mi); } for(PoiPart index : found.getPoiIndexList()) { PoiRegion mi = new PoiRegion(); mi.length = (int) index.getSize(); mi.filePointer = (int) index.getOffset(); mi.name = index.getName(); mi.left31 = index.getLeft(); mi.right31 = index.getRight(); mi.top31 = index.getTop(); mi.bottom31 = index.getBottom(); reader.poiIndexes.add(mi); reader.indexes.add(mi); } for(TransportPart index : found.getTransportIndexList()) { TransportIndex mi = new TransportIndex(); mi.length = (int) index.getSize(); mi.filePointer = (int) index.getOffset(); mi.name = index.getName(); mi.left = index.getLeft(); mi.right =index.getRight(); mi.top = index.getTop(); mi.bottom = index.getBottom(); mi.stopsFileLength = index.getStopsTableLength(); mi.stopsFileOffset = index.getStopsTableOffset(); mi.stringTable = new IndexStringTable(); mi.stringTable.fileOffset = index.getStringTableOffset(); mi.stringTable.length = index.getStringTableLength(); reader.transportIndexes.add(mi); reader.indexes.add(mi); } for(RoutingPart index : found.getRoutingIndexList()) { RouteRegion mi = new RouteRegion(); mi.length = (int) index.getSize(); mi.filePointer = (int) index.getOffset(); mi.name = index.getName(); for(RoutingSubregion mr : index.getSubregionsList()) { RouteSubregion sub = new RouteSubregion(mi); sub.length = (int) mr.getSize(); sub.filePointer = (int) mr.getOffset(); sub.left = mr.getLeft(); sub.right = mr.getRight(); sub.top = mr.getTop(); sub.bottom = mr.getBottom(); sub.shiftToData = mr.getShifToData(); if(mr.getBasemap()) { mi.basesubregions.add(sub); } else { mi.subregions.add(sub); } } reader.routingIndexes.add(mi); reader.indexes.add(mi); } return reader; } public void readFromFile(File f, int version) throws IOException { long time = System.currentTimeMillis(); FileInputStream is = new FileInputStream(f); try { storedIndex = OsmandIndex.OsmAndStoredIndex.newBuilder().mergeFrom(is).build(); hasChanged = false; if(storedIndex.getVersion() != version){ storedIndex = null; } } finally { is.close(); } log.info("Initialize cache " + (System.currentTimeMillis() - time)); } public void writeToFile(File f) throws IOException { if (hasChanged) { FileOutputStream outputStream = new FileOutputStream(f); try { storedIndexBuilder.build().writeTo(outputStream); } finally { outputStream.close(); } } } }