Mapsforge: map stream support

This commit is contained in:
Emux 2020-09-18 14:26:52 +03:00
parent 5c3a728d05
commit 6116ebb348
No known key found for this signature in database
GPG Key ID: 64ED9980896038C3
5 changed files with 189 additions and 124 deletions

View File

@ -2,6 +2,7 @@
## New since 0.14.0
- Mapsforge: map stream support [#784](https://github.com/mapsforge/vtm/pull/784)
- Render theme from Android content providers [#783](https://github.com/mapsforge/vtm/pull/783)
- Many other minor improvements and bug fixes
- [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.15.0)

View File

@ -1,5 +1,6 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2017-2020 devemux86
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
@ -20,7 +21,8 @@ import org.oscim.tiling.source.mapfile.header.SubFileParameter;
import org.oscim.utils.LRUCache;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Level;
@ -44,15 +46,15 @@ class IndexCache {
* SubFileParameter.BYTES_PER_INDEX_ENTRY;
private final Map<IndexCacheEntryKey, byte[]> map;
private final RandomAccessFile randomAccessFile;
private final FileChannel fileChannel;
/**
* @param randomAccessFile the map file from which the index should be read and cached.
* @param capacity the maximum number of entries in the cache.
* @param inputChannel the map file from which the index should be read and cached.
* @param capacity the maximum number of entries in the cache.
* @throws IllegalArgumentException if the capacity is negative.
*/
IndexCache(RandomAccessFile randomAccessFile, int capacity) {
this.randomAccessFile = randomAccessFile;
IndexCache(FileChannel inputChannel, int capacity) {
this.fileChannel = inputChannel;
this.map = Collections.synchronizedMap(new LRUCache<IndexCacheEntryKey, byte[]>(capacity));
}
@ -97,11 +99,14 @@ class IndexCache {
int remainingIndexSize = (int) (subFileParameter.indexEndAddress - indexBlockPosition);
int indexBlockSize = Math.min(SIZE_OF_INDEX_BLOCK, remainingIndexSize);
indexBlock = new byte[indexBlockSize];
ByteBuffer indexBlockWrapper = ByteBuffer.wrap(indexBlock, 0, indexBlockSize);
this.randomAccessFile.seek(indexBlockPosition);
if (this.randomAccessFile.read(indexBlock, 0, indexBlockSize) != indexBlockSize) {
LOG.warning("reading the current index block has failed");
return -1;
synchronized (this.fileChannel) {
this.fileChannel.position(indexBlockPosition);
if (this.fileChannel.read(indexBlockWrapper) != indexBlockSize) {
LOG.warning("reading the current index block has failed");
return -1;
}
}
// put the index block in the map

View File

@ -2,7 +2,7 @@
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013, 2014 Hannes Janetzek
* Copyright 2014-2015 Ludwig M Brinckmann
* Copyright 2016-2019 devemux86
* Copyright 2016-2020 devemux86
* Copyright 2016 Andrey Novikov
* Copyright 2017-2018 Gustl22
* Copyright 2018 Bezzu
@ -38,8 +38,9 @@ import org.oscim.utils.geom.TileSeparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -202,8 +203,7 @@ public class MapDatabase implements ITileDataSource {
private long mFileSize;
private boolean mDebugFile;
private RandomAccessFile mInputFile;
private ReadBuffer mReadBuffer;
private FileChannel mInputChannel;
private String mSignatureBlock;
private String mSignaturePoi;
private String mSignatureWay;
@ -227,11 +227,15 @@ public class MapDatabase implements ITileDataSource {
public MapDatabase(MapFileTileSource tileSource) throws IOException {
mTileSource = tileSource;
try {
/* open the file in read only mode */
mInputFile = new RandomAccessFile(tileSource.mapFile, "r");
mFileSize = mInputFile.length();
mReadBuffer = new ReadBuffer(mInputFile);
// false positive: stream gets closed when the channel is closed
// see e.g. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4796385
if (tileSource.mapFileInputStream != null)
mInputChannel = tileSource.mapFileInputStream.getChannel();
else {
FileInputStream fis = new FileInputStream(tileSource.mapFile);
mInputChannel = fis.getChannel();
}
mFileSize = mInputChannel.size();
} catch (IOException e) {
log.error(e.getMessage());
/* make sure that the file is closed */
@ -314,12 +318,10 @@ public class MapDatabase implements ITileDataSource {
@Override
public void dispose() {
mReadBuffer = null;
if (mInputFile != null) {
if (mInputChannel != null) {
try {
mInputFile.close();
mInputFile = null;
mInputChannel.close();
mInputChannel = null;
} catch (IOException e) {
log.error(e.getMessage());
}
@ -351,13 +353,13 @@ public class MapDatabase implements ITileDataSource {
private void processBlock(QueryParameters queryParameters,
SubFileParameter subFileParameter, ITileDataSink mapDataSink,
BoundingBox boundingBox, Selector selector,
MapReadResult mapReadResult) {
MapReadResult mapReadResult, ReadBuffer readBuffer) {
if (!processBlockSignature()) {
if (!processBlockSignature(readBuffer)) {
return;
}
int[][] zoomTable = readZoomTable(subFileParameter);
int[][] zoomTable = readZoomTable(subFileParameter, readBuffer);
if (zoomTable == null) {
return;
}
@ -366,7 +368,7 @@ public class MapDatabase implements ITileDataSource {
int waysOnQueryZoomLevel = zoomTable[zoomTableRow][1];
/* get the relative offset to the first stored way in the block */
int firstWayOffset = mReadBuffer.readUnsignedInt();
int firstWayOffset = readBuffer.readUnsignedInt();
if (firstWayOffset < 0) {
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
if (mDebugFile) {
@ -376,8 +378,8 @@ public class MapDatabase implements ITileDataSource {
}
/* add the current buffer position to the relative first way offset */
firstWayOffset += mReadBuffer.getBufferPosition();
if (firstWayOffset > mReadBuffer.getBufferSize()) {
firstWayOffset += readBuffer.getBufferPosition();
if (firstWayOffset > readBuffer.getBufferSize()) {
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
if (mDebugFile) {
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
@ -391,13 +393,13 @@ public class MapDatabase implements ITileDataSource {
if (mapReadResult != null)
pois = new ArrayList<>();
if (!processPOIs(mapDataSink, poisOnQueryZoomLevel, boundingBox, filterRequired, pois)) {
if (!processPOIs(mapDataSink, poisOnQueryZoomLevel, boundingBox, filterRequired, pois, readBuffer)) {
return;
}
/* finished reading POIs, check if the current buffer position is valid */
if (mReadBuffer.getBufferPosition() > firstWayOffset) {
log.warn("invalid buffer position: " + mReadBuffer.getBufferPosition());
if (readBuffer.getBufferPosition() > firstWayOffset) {
log.warn("invalid buffer position: " + readBuffer.getBufferPosition());
if (mDebugFile) {
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
}
@ -405,13 +407,13 @@ public class MapDatabase implements ITileDataSource {
}
/* move the pointer to the first way */
mReadBuffer.setBufferPosition(firstWayOffset);
readBuffer.setBufferPosition(firstWayOffset);
List<Way> ways = null;
if (mapReadResult != null && Selector.POIS != selector)
ways = new ArrayList<>();
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel, boundingBox, filterRequired, selector, ways)) {
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel, boundingBox, filterRequired, selector, ways, readBuffer)) {
return;
}
@ -576,10 +578,9 @@ public class MapDatabase implements ITileDataSource {
}
/* seek to the current block in the map file */
mInputFile.seek(subFileParameter.startAddress + blockPointer);
/* read the current block into the buffer */
if (!mReadBuffer.readFromFile(blockSize)) {
ReadBuffer readBuffer = new ReadBuffer(mInputChannel);
if (!readBuffer.readFromFile(subFileParameter.startAddress + blockPointer, blockSize)) {
/* skip the current block */
log.warn("reading current block has failed: " + blockSize);
return;
@ -596,7 +597,7 @@ public class MapDatabase implements ITileDataSource {
mTileLatitude = (int) (tileLatitudeDeg * 1E6);
mTileLongitude = (int) (tileLongitudeDeg * 1E6);
processBlock(queryParams, subFileParameter, mapDataSink, boundingBox, selector, mapReadResult);
processBlock(queryParams, subFileParameter, mapDataSink, boundingBox, selector, mapReadResult, readBuffer);
}
}
}
@ -607,10 +608,10 @@ public class MapDatabase implements ITileDataSource {
* @return true if the block signature could be processed successfully,
* false otherwise.
*/
private boolean processBlockSignature() {
private boolean processBlockSignature(ReadBuffer readBuffer) {
if (mDebugFile) {
/* get and check the block signature */
mSignatureBlock = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_BLOCK);
mSignatureBlock = readBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_BLOCK);
if (!mSignatureBlock.startsWith("###TileStart")) {
log.warn("invalid block signature: " + mSignatureBlock);
return false;
@ -628,7 +629,7 @@ public class MapDatabase implements ITileDataSource {
* otherwise.
*/
private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois, BoundingBox boundingBox,
boolean filterRequired, List<PointOfInterest> pois) {
boolean filterRequired, List<PointOfInterest> pois, ReadBuffer readBuffer) {
Tag[] poiTags = mTileSource.fileInfo.poiTags;
MapElement e = mElem;
@ -638,7 +639,7 @@ public class MapDatabase implements ITileDataSource {
if (mDebugFile) {
/* get and check the POI signature */
mSignaturePoi = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI);
mSignaturePoi = readBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI);
if (!mSignaturePoi.startsWith("***POIStart")) {
log.warn("invalid POI signature: " + mSignaturePoi);
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
@ -647,12 +648,12 @@ public class MapDatabase implements ITileDataSource {
}
/* get the POI latitude offset (VBE-S) */
int latitude = mTileLatitude + mReadBuffer.readSignedInt();
int latitude = mTileLatitude + readBuffer.readSignedInt();
/* get the POI longitude offset (VBE-S) */
int longitude = mTileLongitude + mReadBuffer.readSignedInt();
int longitude = mTileLongitude + readBuffer.readSignedInt();
/* get the special byte which encodes multiple flags */
byte specialByte = mReadBuffer.readByte();
byte specialByte = readBuffer.readByte();
/* bit 1-4 represent the layer */
byte layer = (byte) ((specialByte & POI_LAYER_BITMASK) >>> POI_LAYER_SHIFT);
@ -661,29 +662,29 @@ public class MapDatabase implements ITileDataSource {
byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK);
if (numberOfTags != 0) {
if (!mReadBuffer.readTags(e.tags, poiTags, numberOfTags))
if (!readBuffer.readTags(e.tags, poiTags, numberOfTags))
return false;
}
/* get the feature bitmask (1 byte) */
byte featureByte = mReadBuffer.readByte();
byte featureByte = readBuffer.readByte();
/* bit 1-3 enable optional features
* check if the POI has a name */
if ((featureByte & POI_FEATURE_NAME) != 0) {
String str = mTileSource.extractLocalized(mReadBuffer.readUTF8EncodedString());
String str = mTileSource.extractLocalized(readBuffer.readUTF8EncodedString());
e.tags.add(new Tag(Tag.KEY_NAME, str, false));
}
/* check if the POI has a house number */
if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) {
String str = mReadBuffer.readUTF8EncodedString();
String str = readBuffer.readUTF8EncodedString();
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
}
/* check if the POI has an elevation */
if ((featureByte & POI_FEATURE_ELEVATION) != 0) {
String str = Integer.toString(mReadBuffer.readSignedInt());
String str = Integer.toString(readBuffer.readSignedInt());
e.tags.add(new Tag(Tag.KEY_ELE, str, false));
}
mTileProjection.projectPoint(latitude, longitude, e);
@ -712,9 +713,9 @@ public class MapDatabase implements ITileDataSource {
return true;
}
private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine, List<GeoPoint[]> wayCoordinates, int[] labelPosition) {
private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine, List<GeoPoint[]> wayCoordinates, int[] labelPosition, ReadBuffer readBuffer) {
/* get and check the number of way coordinate blocks (VBE-U) */
int numBlocks = mReadBuffer.readUnsignedInt();
int numBlocks = readBuffer.readUnsignedInt();
if (numBlocks < 1 || numBlocks > Short.MAX_VALUE) {
log.warn("invalid number of way coordinate blocks: " + numBlocks);
return false;
@ -726,7 +727,7 @@ public class MapDatabase implements ITileDataSource {
/* read the way coordinate blocks */
for (int coordinateBlock = 0; coordinateBlock < numBlocks; ++coordinateBlock) {
int numWayNodes = mReadBuffer.readUnsignedInt();
int numWayNodes = readBuffer.readUnsignedInt();
if (numWayNodes < 2 || numWayNodes > Short.MAX_VALUE) {
log.warn("invalid number of way nodes: " + numWayNodes);
@ -744,7 +745,7 @@ public class MapDatabase implements ITileDataSource {
// label position must be set on first coordinate block
wayLengths[coordinateBlock] = decodeWayNodes(doubleDeltaEncoding, e, len, isLine,
coordinateBlock == 0 ? labelPosition : null, waySegment);
coordinateBlock == 0 ? labelPosition : null, waySegment, readBuffer);
if (wayCoordinates != null)
wayCoordinates.add(waySegment);
@ -753,9 +754,9 @@ public class MapDatabase implements ITileDataSource {
return true;
}
private int decodeWayNodes(boolean doubleDelta, MapElement e, int length, boolean isLine, int[] labelPosition, GeoPoint[] waySegment) {
private int decodeWayNodes(boolean doubleDelta, MapElement e, int length, boolean isLine, int[] labelPosition, GeoPoint[] waySegment, ReadBuffer readBuffer) {
int[] buffer = mIntBuffer;
mReadBuffer.readSignedInt(buffer, length);
readBuffer.readSignedInt(buffer, length);
float[] outBuffer = e.ensurePointSize(e.pointNextPos + length, true);
int outPos = e.pointNextPos;
@ -848,7 +849,7 @@ public class MapDatabase implements ITileDataSource {
*/
private boolean processWays(QueryParameters queryParameters, ITileDataSink mapDataSink,
int numberOfWays, BoundingBox boundingBox, boolean filterRequired,
Selector selector, List<Way> ways) {
Selector selector, List<Way> ways, ReadBuffer readBuffer) {
Tag[] wayTags = mTileSource.fileInfo.wayTags;
MapElement e = mElem;
@ -860,9 +861,9 @@ public class MapDatabase implements ITileDataSource {
stringOffset = 0;
if (mTileSource.experimental) {
stringsSize = mReadBuffer.readUnsignedInt();
stringOffset = mReadBuffer.getBufferPosition();
mReadBuffer.skipBytes(stringsSize);
stringsSize = readBuffer.readUnsignedInt();
stringOffset = readBuffer.getBufferPosition();
readBuffer.skipBytes(stringsSize);
}
//setTileClipping(queryParameters);
@ -873,7 +874,7 @@ public class MapDatabase implements ITileDataSource {
if (mDebugFile) {
// get and check the way signature
mSignatureWay = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_WAY);
mSignatureWay = readBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_WAY);
if (!mSignatureWay.startsWith("---WayStart")) {
log.warn("invalid way signature: " + mSignatureWay);
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
@ -882,7 +883,7 @@ public class MapDatabase implements ITileDataSource {
}
if (queryParameters.useTileBitmask) {
elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask,
elementCounter = readBuffer.skipWays(queryParameters.queryTileBitmask,
elementCounter);
if (elementCounter == 0)
@ -891,19 +892,19 @@ public class MapDatabase implements ITileDataSource {
if (elementCounter < 0)
return false;
if (mTileSource.experimental && mReadBuffer.lastTagPosition > 0) {
int pos = mReadBuffer.getBufferPosition();
mReadBuffer.setBufferPosition(mReadBuffer.lastTagPosition);
if (mTileSource.experimental && readBuffer.lastTagPosition > 0) {
int pos = readBuffer.getBufferPosition();
readBuffer.setBufferPosition(readBuffer.lastTagPosition);
byte numberOfTags =
(byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK);
if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags))
(byte) (readBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK);
if (!readBuffer.readTags(e.tags, wayTags, numberOfTags))
return false;
mReadBuffer.setBufferPosition(pos);
readBuffer.setBufferPosition(pos);
}
} else {
int wayDataSize = mReadBuffer.readUnsignedInt();
int wayDataSize = readBuffer.readUnsignedInt();
if (wayDataSize < 0) {
log.warn("invalid way data size: " + wayDataSize);
if (mDebugFile) {
@ -914,11 +915,11 @@ public class MapDatabase implements ITileDataSource {
}
/* ignore the way tile bitmask (2 bytes) */
mReadBuffer.skipBytes(2);
readBuffer.skipBytes(2);
}
/* get the special byte which encodes multiple flags */
byte specialByte = mReadBuffer.readByte();
byte specialByte = readBuffer.readByte();
/* bit 1-4 represent the layer */
byte layer = (byte) ((specialByte & WAY_LAYER_BITMASK) >>> WAY_LAYER_SHIFT);
@ -926,12 +927,12 @@ public class MapDatabase implements ITileDataSource {
byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK);
if (numberOfTags != 0) {
if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags))
if (!readBuffer.readTags(e.tags, wayTags, numberOfTags))
return false;
}
/* get the feature bitmask (1 byte) */
byte featureByte = mReadBuffer.readByte();
byte featureByte = readBuffer.readByte();
/* bit 1-6 enable optional features */
boolean featureWayDoubleDeltaEncoding =
@ -943,42 +944,42 @@ public class MapDatabase implements ITileDataSource {
if (mTileSource.experimental) {
if (hasName) {
int textPos = mReadBuffer.readUnsignedInt();
String str = mTileSource.extractLocalized(mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos));
int textPos = readBuffer.readUnsignedInt();
String str = mTileSource.extractLocalized(readBuffer.readUTF8EncodedStringAt(stringOffset + textPos));
e.tags.add(new Tag(Tag.KEY_NAME, str, false));
}
if (hasHouseNr) {
int textPos = mReadBuffer.readUnsignedInt();
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
int textPos = readBuffer.readUnsignedInt();
String str = readBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
}
if (hasRef) {
int textPos = mReadBuffer.readUnsignedInt();
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
int textPos = readBuffer.readUnsignedInt();
String str = readBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
e.tags.add(new Tag(Tag.KEY_REF, str, false));
}
} else {
if (hasName) {
String str = mTileSource.extractLocalized(mReadBuffer.readUTF8EncodedString());
String str = mTileSource.extractLocalized(readBuffer.readUTF8EncodedString());
e.tags.add(new Tag(Tag.KEY_NAME, str, false));
}
if (hasHouseNr) {
String str = mReadBuffer.readUTF8EncodedString();
String str = readBuffer.readUTF8EncodedString();
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
}
if (hasRef) {
String str = mReadBuffer.readUTF8EncodedString();
String str = readBuffer.readUTF8EncodedString();
e.tags.add(new Tag(Tag.KEY_REF, str, false));
}
}
int[] labelPosition = null;
if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0) {
labelPosition = readOptionalLabelPosition();
labelPosition = readOptionalLabelPosition(readBuffer);
}
if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) {
wayDataBlocks = mReadBuffer.readUnsignedInt();
wayDataBlocks = readBuffer.readUnsignedInt();
if (wayDataBlocks < 1) {
log.warn("invalid number of way data blocks: " + wayDataBlocks);
@ -999,7 +1000,7 @@ public class MapDatabase implements ITileDataSource {
if (ways != null)
wayNodes = new ArrayList<>();
if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature, wayNodes, labelPosition))
if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature, wayNodes, labelPosition, readBuffer))
return false;
/* drop invalid outer ring */
@ -1152,14 +1153,14 @@ public class MapDatabase implements ITileDataSource {
return mapReadResult;
}
private int[] readOptionalLabelPosition() {
private int[] readOptionalLabelPosition(ReadBuffer readBuffer) {
int[] labelPosition = new int[2];
/* get the label position latitude offset (VBE-S) */
labelPosition[1] = mReadBuffer.readSignedInt();
labelPosition[1] = readBuffer.readSignedInt();
/* get the label position longitude offset (VBE-S) */
labelPosition[0] = mReadBuffer.readSignedInt();
labelPosition[0] = readBuffer.readSignedInt();
return labelPosition;
}
@ -1187,7 +1188,7 @@ public class MapDatabase implements ITileDataSource {
return readMapData(upperLeft, lowerRight, Selector.POIS);
}
private int[][] readZoomTable(SubFileParameter subFileParameter) {
private int[][] readZoomTable(SubFileParameter subFileParameter, ReadBuffer readBuffer) {
int rows = subFileParameter.zoomLevelMax - subFileParameter.zoomLevelMin + 1;
int[][] zoomTable = new int[rows][2];
@ -1195,8 +1196,8 @@ public class MapDatabase implements ITileDataSource {
int cumulatedNumberOfWays = 0;
for (int row = 0; row < rows; row++) {
cumulatedNumberOfPois += mReadBuffer.readUnsignedInt();
cumulatedNumberOfWays += mReadBuffer.readUnsignedInt();
cumulatedNumberOfPois += readBuffer.readUnsignedInt();
cumulatedNumberOfWays += readBuffer.readUnsignedInt();
zoomTable[row][0] = cumulatedNumberOfPois;
zoomTable[row][1] = cumulatedNumberOfWays;

View File

@ -1,7 +1,7 @@
/*
* Copyright 2013 mapsforge.org
* Copyright 2013 Hannes Janetzek
* Copyright 2016-2018 devemux86
* Copyright 2016-2020 devemux86
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
@ -25,13 +25,13 @@ import org.oscim.tiling.OverzoomTileDataSource;
import org.oscim.tiling.TileSource;
import org.oscim.tiling.source.mapfile.header.MapFileHeader;
import org.oscim.tiling.source.mapfile.header.MapFileInfo;
import org.oscim.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
public class MapFileTileSource extends TileSource implements IMapFileTileSource {
private static final Logger log = LoggerFactory.getLogger(MapFileTileSource.class);
@ -40,14 +40,14 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
* Amount of cache blocks that the index cache should store.
*/
private static final int INDEX_CACHE_SIZE = 64;
private static final String READ_ONLY_MODE = "r";
MapFileHeader fileHeader;
MapFileInfo fileInfo;
IndexCache databaseIndexCache;
boolean experimental;
File mapFile;
private RandomAccessFile mInputFile;
FileInputStream mapFileInputStream;
private FileChannel inputChannel;
/**
* The preferred language when extracting labels from this tile source.
@ -98,6 +98,10 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
return true;
}
public void setMapFileInputStream(FileInputStream fileInputStream) {
this.mapFileInputStream = fileInputStream;
}
@Override
public void setPreferredLanguage(String preferredLanguage) {
this.preferredLanguage = preferredLanguage;
@ -105,31 +109,38 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
@Override
public OpenResult open() {
if (!options.containsKey("file"))
if (mapFileInputStream == null && !options.containsKey("file"))
return new OpenResult("no map file set");
try {
// make sure to close any previously opened file first
//close();
// false positive: stream gets closed when the channel is closed
// see e.g. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4796385
File file = null;
if (mapFileInputStream != null)
inputChannel = mapFileInputStream.getChannel();
else {
// make sure to close any previously opened file first
//close();
File file = new File(options.get("file"));
file = new File(options.get("file"));
// check if the file exists and is readable
if (!file.exists()) {
return new OpenResult("file does not exist: " + file);
} else if (!file.isFile()) {
return new OpenResult("not a file: " + file);
} else if (!file.canRead()) {
return new OpenResult("cannot read file: " + file);
// check if the file exists and is readable
if (!file.exists()) {
return new OpenResult("file does not exist: " + file);
} else if (!file.isFile()) {
return new OpenResult("not a file: " + file);
} else if (!file.canRead()) {
return new OpenResult("cannot read file: " + file);
}
FileInputStream fis = new FileInputStream(file);
inputChannel = fis.getChannel();
}
// open the file in read only mode
mInputFile = new RandomAccessFile(file, READ_ONLY_MODE);
long mFileSize = mInputFile.length();
ReadBuffer mReadBuffer = new ReadBuffer(mInputFile);
long fileSize = inputChannel.size();
ReadBuffer readBuffer = new ReadBuffer(inputChannel);
fileHeader = new MapFileHeader();
OpenResult openResult = fileHeader.readHeader(mReadBuffer, mFileSize);
OpenResult openResult = fileHeader.readHeader(readBuffer, fileSize);
if (!openResult.isSuccess()) {
close();
@ -137,10 +148,7 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
}
fileInfo = fileHeader.getMapFileInfo();
mapFile = file;
databaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE);
// Experimental?
//experimental = fileInfo.fileVersion == 4;
databaseIndexCache = new IndexCache(inputChannel, INDEX_CACHE_SIZE);
log.debug("File version: " + fileInfo.fileVersion);
return OpenResult.SUCCESS;
@ -164,8 +172,14 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
@Override
public void close() {
IOUtils.closeQuietly(mInputFile);
mInputFile = null;
if (inputChannel != null) {
try {
inputChannel.close();
inputChannel = null;
} catch (IOException e) {
log.error(e.getMessage());
}
}
fileHeader = null;
fileInfo = null;
mapFile = null;

View File

@ -25,6 +25,8 @@ import org.oscim.utils.Parameters;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
@ -39,12 +41,13 @@ public class ReadBuffer {
private byte[] mBufferData;
private int mBufferPosition;
private final RandomAccessFile mInputFile;
private ByteBuffer mBufferWrapper;
private final FileChannel mInputChannel;
private final List<Integer> mTagIds = new ArrayList<>();
ReadBuffer(RandomAccessFile inputFile) {
mInputFile = inputFile;
ReadBuffer(FileChannel inputChannel) {
mInputChannel = inputChannel;
}
/**
@ -91,13 +94,54 @@ public class ReadBuffer {
LOG.log(Level.SEVERE, t.getMessage(), t);
return false;
}
mBufferWrapper = ByteBuffer.wrap(mBufferData, 0, length);
}
mBufferPosition = 0;
mBufferWrapper.clear();
// reset the buffer position and read the data into the buffer
// bufferPosition = 0;
return mInputFile.read(mBufferData, 0, length) == length;
return mInputChannel.read(mBufferWrapper) == length;
}
/**
* Reads the given amount of bytes from the file into the read buffer and
* resets the internal buffer position. If
* the capacity of the read buffer is too small, a larger one is created
* automatically.
*
* @param offset the offset position, measured in bytes from the beginning of the file, at which to set the file pointer.
* @param length the amount of bytes to read from the file.
* @return true if the whole data was read successfully, false otherwise.
* @throws IOException if an error occurs while reading the file.
*/
public boolean readFromFile(long offset, int length) throws IOException {
// ensure that the read buffer is large enough
if (mBufferData == null || mBufferData.length < length) {
// ensure that the read buffer is not too large
if (length > Parameters.MAXIMUM_BUFFER_SIZE) {
LOG.warning("invalid read length: " + length);
return false;
}
try {
mBufferData = new byte[length];
} catch (Throwable t) {
LOG.log(Level.SEVERE, t.getMessage(), t);
return false;
}
mBufferWrapper = ByteBuffer.wrap(mBufferData, 0, length);
}
mBufferPosition = 0;
mBufferWrapper.clear();
// reset the buffer position and read the data into the buffer
// bufferPosition = 0;
synchronized (mInputChannel) {
mInputChannel.position(offset);
return mInputChannel.read(mBufferWrapper) == length;
}
}
/**