testing mapnik vector datasource
This commit is contained in:
parent
b92afea6d1
commit
6ff66a7567
@ -45,7 +45,8 @@ public final class MapDatabaseFactory {
|
|||||||
case TEST_READER:
|
case TEST_READER:
|
||||||
return new org.oscim.database.test.MapDatabase();
|
return new org.oscim.database.test.MapDatabase();
|
||||||
case PBMAP_READER:
|
case PBMAP_READER:
|
||||||
return new org.oscim.database.pbmap.MapDatabase();
|
//return new org.oscim.database.pbmap.MapDatabase();
|
||||||
|
return new org.oscim.database.mapnik.MapDatabase();
|
||||||
case OSCIMAP_READER:
|
case OSCIMAP_READER:
|
||||||
return new org.oscim.database.oscimap.MapDatabase();
|
return new org.oscim.database.oscimap.MapDatabase();
|
||||||
default:
|
default:
|
||||||
|
397
src/org/oscim/database/mapnik/LwHttp.java
Normal file
397
src/org/oscim/database/mapnik/LwHttp.java
Normal file
@ -0,0 +1,397 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.database.mapnik;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class LwHttp {
|
||||||
|
private static final String TAG = LwHttp.class.getName();
|
||||||
|
private final static int BUFFER_SIZE = 65536;
|
||||||
|
|
||||||
|
//
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// position in buffer
|
||||||
|
int bufferPos;
|
||||||
|
|
||||||
|
// bytes available in buffer
|
||||||
|
int bufferFill;
|
||||||
|
|
||||||
|
// offset of buffer in message
|
||||||
|
private int mBufferOffset;
|
||||||
|
|
||||||
|
private String mHost;
|
||||||
|
private int mPort;
|
||||||
|
private InputStream mInputStream;
|
||||||
|
|
||||||
|
private int mMaxReq = 0;
|
||||||
|
private Socket mSocket;
|
||||||
|
private OutputStream mCommandStream;
|
||||||
|
private BufferedInputStream mResponseStream;
|
||||||
|
long mLastRequest = 0;
|
||||||
|
private SocketAddress mSockAddr;
|
||||||
|
|
||||||
|
//private final static byte[] RESPONSE_HTTP_OK = "HTTP/1.1 200 OK".getBytes();
|
||||||
|
private final static byte[] RESPONSE_HTTP_OK = "200 OK".getBytes();
|
||||||
|
private final static byte[] RESPONSE_CONTENT_LEN = "Content-Length: ".getBytes();
|
||||||
|
private final static int RESPONSE_EXPECTED_LIVES = 100;
|
||||||
|
private final static int RESPONSE_EXPECTED_TIMEOUT = 10000;
|
||||||
|
|
||||||
|
private byte[] REQUEST_GET_START;
|
||||||
|
private byte[] REQUEST_GET_END;
|
||||||
|
|
||||||
|
private byte[] mRequestBuffer;
|
||||||
|
|
||||||
|
boolean setServer(String urlString) {
|
||||||
|
urlString = "http://d1s11ojcu7opje.cloudfront.net/dev/764e0b8d";
|
||||||
|
|
||||||
|
URL url;
|
||||||
|
try {
|
||||||
|
url = new URL(urlString);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
//return new OpenResult("invalid url: " + options.get("url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = url.getPort();
|
||||||
|
if (port < 0)
|
||||||
|
port = 80;
|
||||||
|
|
||||||
|
String host = url.getHost();
|
||||||
|
String path = url.getPath();
|
||||||
|
Log.d(TAG, "open database: " + host + " " + port + " " + path);
|
||||||
|
|
||||||
|
REQUEST_GET_START = ("GET " + path).getBytes();
|
||||||
|
REQUEST_GET_END = (".vector.pbf HTTP/1.1\n" +
|
||||||
|
"User-Agent: Wget/1.13.4 (linux-gnu)\n" +
|
||||||
|
"Accept: */*\n" +
|
||||||
|
"Host: " + host + "\n" +
|
||||||
|
"Connection: Keep-Alive\n\n").getBytes();
|
||||||
|
|
||||||
|
mHost = host;
|
||||||
|
mPort = port;
|
||||||
|
|
||||||
|
mRequestBuffer = new byte[1024];
|
||||||
|
System.arraycopy(REQUEST_GET_START, 0,
|
||||||
|
mRequestBuffer, 0, REQUEST_GET_START.length);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
if (mSocket != null) {
|
||||||
|
try {
|
||||||
|
mSocket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
mSocket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int readHeader() throws IOException {
|
||||||
|
|
||||||
|
InputStream is = mResponseStream;
|
||||||
|
mResponseStream.mark(1 << 16);
|
||||||
|
|
||||||
|
byte[] buf = buffer;
|
||||||
|
boolean first = true;
|
||||||
|
int read = 0;
|
||||||
|
int pos = 0;
|
||||||
|
int end = 0;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
int contentLength = 0;
|
||||||
|
|
||||||
|
// header cannot be larger than BUFFER_SIZE for this to work
|
||||||
|
for (; pos < read || (len = is.read(buf, read, BUFFER_SIZE - read)) >= 0; len = 0) {
|
||||||
|
read += len;
|
||||||
|
while (end < read && (buf[end] != '\n'))
|
||||||
|
end++;
|
||||||
|
|
||||||
|
if (buf[end] == '\n') {
|
||||||
|
if (first) {
|
||||||
|
// check only for OK
|
||||||
|
first = false;
|
||||||
|
if (!compareBytes(buf, pos + 9, end, RESPONSE_HTTP_OK, 6)){
|
||||||
|
String line = new String(buf, pos, end - pos - 1);
|
||||||
|
Log.d(TAG, ">" + line + "< ");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (end - pos == 1) {
|
||||||
|
// check empty line (header end)
|
||||||
|
end += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// parse Content-Length, TODO just encode this with message
|
||||||
|
for (int i = 0; pos + i < end - 1; i++) {
|
||||||
|
if (i < 16) {
|
||||||
|
if (buf[pos + i] == RESPONSE_CONTENT_LEN[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read int value
|
||||||
|
contentLength = contentLength * 10 + (buf[pos + i]) - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//String line = new String(buf, pos, end - pos - 1);
|
||||||
|
//Log.d(TAG, ">" + line + "< ");
|
||||||
|
|
||||||
|
pos += (end - pos) + 1;
|
||||||
|
end = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// back to start of content
|
||||||
|
mResponseStream.reset();
|
||||||
|
mResponseStream.mark(0);
|
||||||
|
mResponseStream.skip(end);
|
||||||
|
|
||||||
|
// start of content
|
||||||
|
bufferPos = 0;
|
||||||
|
mBufferOffset = 0;
|
||||||
|
|
||||||
|
// buffer fill
|
||||||
|
bufferFill = 0;
|
||||||
|
|
||||||
|
// decode zlib compressed content
|
||||||
|
mInputStream = new InflaterInputStream(mResponseStream);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean sendRequest(Tile tile) throws IOException {
|
||||||
|
|
||||||
|
bufferFill = 0;
|
||||||
|
bufferPos = 0;
|
||||||
|
//mReadPos = 0;
|
||||||
|
|
||||||
|
if (mSocket != null && ((mMaxReq-- <= 0)
|
||||||
|
|| (SystemClock.elapsedRealtime() - mLastRequest
|
||||||
|
> RESPONSE_EXPECTED_TIMEOUT))) {
|
||||||
|
try {
|
||||||
|
mSocket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log.d(TAG, "not alive - recreate connection " + mMaxReq);
|
||||||
|
mSocket = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSocket == null) {
|
||||||
|
lwHttpConnect();
|
||||||
|
// we know our server
|
||||||
|
mMaxReq = RESPONSE_EXPECTED_LIVES;
|
||||||
|
// Log.d(TAG, "create connection");
|
||||||
|
} else {
|
||||||
|
// should not be needed
|
||||||
|
int avail = mResponseStream.available();
|
||||||
|
if (avail > 0) {
|
||||||
|
Log.d(TAG, "Consume left-over bytes: " + avail);
|
||||||
|
mResponseStream.read(buffer, 0, avail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] request = mRequestBuffer;
|
||||||
|
int pos = REQUEST_GET_START.length;
|
||||||
|
|
||||||
|
request[pos++] = '/';
|
||||||
|
request[pos++] = pos2hex(tile.tileX);
|
||||||
|
request[pos++] = pos2hex(tile.tileY);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.zoomLevel, pos, request);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.tileX, pos, request);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.tileY, pos, request);
|
||||||
|
|
||||||
|
int len = REQUEST_GET_END.length;
|
||||||
|
System.arraycopy(REQUEST_GET_END, 0, request, pos, len);
|
||||||
|
len += pos;
|
||||||
|
|
||||||
|
//Log.d(TAG, "request " + new String(request,0,len));
|
||||||
|
// this does the same but with a few more allocations:
|
||||||
|
// byte[] request = String.format(REQUEST,
|
||||||
|
// Integer.valueOf(tile.zoomLevel),
|
||||||
|
// Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes();
|
||||||
|
|
||||||
|
try {
|
||||||
|
mCommandStream.write(request, 0, len);
|
||||||
|
mCommandStream.flush();
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "recreate connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
lwHttpConnect();
|
||||||
|
|
||||||
|
mCommandStream.write(request, 0, len);
|
||||||
|
mCommandStream.flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static byte[] hexTable = {
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||||
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||||
|
|
||||||
|
private static byte pos2hex(int pos){
|
||||||
|
return hexTable[(pos % 16)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean lwHttpConnect() throws IOException {
|
||||||
|
if (mSockAddr == null)
|
||||||
|
mSockAddr = new InetSocketAddress(mHost, mPort);
|
||||||
|
|
||||||
|
mSocket = new Socket();
|
||||||
|
mSocket.connect(mSockAddr, 30000);
|
||||||
|
mSocket.setTcpNoDelay(true);
|
||||||
|
|
||||||
|
mCommandStream = mSocket.getOutputStream();
|
||||||
|
mResponseStream = new BufferedInputStream(mSocket.getInputStream());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write (positive) integer as char sequence to buffer
|
||||||
|
private static int writeInt(int val, int pos, byte[] buf) {
|
||||||
|
if (val == 0) {
|
||||||
|
buf[pos] = '0';
|
||||||
|
return pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int n = val; n > 0; n = n / 10, i++)
|
||||||
|
buf[pos + i] = (byte) ('0' + n % 10);
|
||||||
|
|
||||||
|
// reverse bytes
|
||||||
|
for (int j = pos, end = pos + i - 1, mid = pos + i / 2; j < mid; j++, end--) {
|
||||||
|
byte tmp = buf[j];
|
||||||
|
buf[j] = buf[end];
|
||||||
|
buf[end] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean compareBytes(byte[] buffer, int position, int available,
|
||||||
|
byte[] string, int length) {
|
||||||
|
|
||||||
|
if (available - position < length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
if (buffer[position + i] != string[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decodeInt(byte[] buffer, int offset) {
|
||||||
|
return buffer[offset] << 24 | (buffer[offset + 1] & 0xff) << 16
|
||||||
|
| (buffer[offset + 2] & 0xff) << 8
|
||||||
|
| (buffer[offset + 3] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasData() {
|
||||||
|
try {
|
||||||
|
return readBuffer(1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int position() {
|
||||||
|
return mBufferOffset + bufferPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readBuffer(int size) throws IOException {
|
||||||
|
// check if buffer already contains the request bytes
|
||||||
|
if (bufferPos + size < bufferFill)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// check if inputstream is read to the end
|
||||||
|
//if (mReadPos == mReadEnd)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
int maxSize = buffer.length;
|
||||||
|
|
||||||
|
if (size > maxSize) {
|
||||||
|
Log.d(TAG, "increase read buffer to " + size + " bytes");
|
||||||
|
maxSize = size;
|
||||||
|
byte[] tmp = new byte[maxSize];
|
||||||
|
bufferFill -= bufferPos;
|
||||||
|
System.arraycopy(buffer, bufferPos, tmp, 0, bufferFill);
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
buffer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferFill == bufferPos) {
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
bufferFill = 0;
|
||||||
|
} else if (bufferPos + size > maxSize) {
|
||||||
|
// copy bytes left to the beginning of buffer
|
||||||
|
bufferFill -= bufferPos;
|
||||||
|
System.arraycopy(buffer, bufferPos, buffer, 0, bufferFill);
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max = maxSize - bufferFill;
|
||||||
|
|
||||||
|
while ((bufferFill - bufferPos) < size && max > 0) {
|
||||||
|
|
||||||
|
max = maxSize - bufferFill;
|
||||||
|
|
||||||
|
// read until requested size is available in buffer
|
||||||
|
int len = mInputStream.read(buffer, bufferFill, max);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
// finished reading, mark end
|
||||||
|
buffer[bufferFill] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferFill += len;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
899
src/org/oscim/database/mapnik/MapDatabase.java
Normal file
899
src/org/oscim/database/mapnik/MapDatabase.java
Normal file
@ -0,0 +1,899 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.database.mapnik;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.oscim.core.BoundingBox;
|
||||||
|
import org.oscim.core.GeoPoint;
|
||||||
|
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||||
|
import org.oscim.core.MapElement;
|
||||||
|
import org.oscim.core.Tag;
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
import org.oscim.database.IMapDatabase;
|
||||||
|
import org.oscim.database.IMapDatabaseCallback;
|
||||||
|
import org.oscim.database.MapInfo;
|
||||||
|
import org.oscim.database.MapOptions;
|
||||||
|
import org.oscim.layers.tile.MapTile;
|
||||||
|
import org.oscim.utils.UTF8Decoder;
|
||||||
|
import org.oscim.utils.pool.Inlist;
|
||||||
|
import org.oscim.utils.pool.Pool;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class MapDatabase implements IMapDatabase {
|
||||||
|
private static final String TAG = MapDatabase.class.getName();
|
||||||
|
|
||||||
|
private static final MapInfo mMapInfo =
|
||||||
|
new MapInfo(new BoundingBox(-180, -90, 180, 90),
|
||||||
|
new Byte((byte) 4), new GeoPoint(53.11, 8.85),
|
||||||
|
null, 0, 0, 0, "de", "comment", "author",
|
||||||
|
new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }
|
||||||
|
);
|
||||||
|
|
||||||
|
private final static float REF_TILE_SIZE = 4096.0f;
|
||||||
|
|
||||||
|
// 'open' state
|
||||||
|
private boolean mOpen = false;
|
||||||
|
|
||||||
|
private IMapDatabaseCallback mMapGenerator;
|
||||||
|
private float mScaleFactor;
|
||||||
|
private MapTile mTile;
|
||||||
|
|
||||||
|
private LwHttp lwHttp;
|
||||||
|
|
||||||
|
private final UTF8Decoder mStringDecoder;
|
||||||
|
|
||||||
|
//private final MapElement mElem;
|
||||||
|
|
||||||
|
public MapDatabase() {
|
||||||
|
mStringDecoder = new UTF8Decoder();
|
||||||
|
//mElem = new MapElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult executeQuery(MapTile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||||
|
QueryResult result = QueryResult.SUCCESS;
|
||||||
|
|
||||||
|
mTile = tile;
|
||||||
|
|
||||||
|
mMapGenerator = mapDatabaseCallback;
|
||||||
|
|
||||||
|
// scale coordinates to tile size
|
||||||
|
mScaleFactor = REF_TILE_SIZE / Tile.SIZE;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (lwHttp.sendRequest(tile) && lwHttp.readHeader() >= 0) {
|
||||||
|
decode();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, tile + " Network Error");
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
} catch (SocketException ex) {
|
||||||
|
Log.d(TAG, tile + " Socket exception: " + ex.getMessage());
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
} catch (SocketTimeoutException ex) {
|
||||||
|
Log.d(TAG, tile + " Socket Timeout exception: " + ex.getMessage());
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
} catch (UnknownHostException ex) {
|
||||||
|
Log.d(TAG, tile + " no network");
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
lwHttp.mLastRequest = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
|
if (result != QueryResult.SUCCESS) {
|
||||||
|
lwHttp.close();
|
||||||
|
}
|
||||||
|
Log.d(TAG, ">>> " + result + " >>> " + mTile);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapInfo getMapInfo() {
|
||||||
|
return mMapInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return mOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenResult open(MapOptions options) {
|
||||||
|
if (mOpen)
|
||||||
|
return OpenResult.SUCCESS;
|
||||||
|
|
||||||
|
if (options == null || !options.containsKey("url"))
|
||||||
|
return new OpenResult("options missing");
|
||||||
|
|
||||||
|
lwHttp = new LwHttp();
|
||||||
|
|
||||||
|
if (!lwHttp.setServer(options.get("url"))) {
|
||||||
|
return new OpenResult("invalid url: " + options.get("url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpen = true;
|
||||||
|
initDecorder();
|
||||||
|
|
||||||
|
return OpenResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
mOpen = false;
|
||||||
|
lwHttp.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMapProjection() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int TAG_TILE_LAYERS = 3;
|
||||||
|
|
||||||
|
private static final int TAG_LAYER_VERSION = 15;
|
||||||
|
private static final int TAG_LAYER_NAME = 1;
|
||||||
|
private static final int TAG_LAYER_FEATURES = 2;
|
||||||
|
private static final int TAG_LAYER_KEYS = 3;
|
||||||
|
private static final int TAG_LAYER_VALUES = 4;
|
||||||
|
private static final int TAG_LAYER_EXTENT = 5;
|
||||||
|
|
||||||
|
private static final int TAG_FEATURE_ID = 1;
|
||||||
|
private static final int TAG_FEATURE_TAGS = 2;
|
||||||
|
private static final int TAG_FEATURE_TYPE = 3;
|
||||||
|
private static final int TAG_FEATURE_GEOMETRY = 4;
|
||||||
|
|
||||||
|
private static final int TAG_VALUE_STRING = 1;
|
||||||
|
private static final int TAG_VALUE_FLOAT = 2;
|
||||||
|
private static final int TAG_VALUE_DOUBLE = 3;
|
||||||
|
private static final int TAG_VALUE_LONG = 4;
|
||||||
|
private static final int TAG_VALUE_UINT = 5;
|
||||||
|
private static final int TAG_VALUE_SINT = 6;
|
||||||
|
private static final int TAG_VALUE_BOOL = 7;
|
||||||
|
|
||||||
|
private static final int TAG_GEOM_UNKNOWN = 0;
|
||||||
|
private static final int TAG_GEOM_POINT = 1;
|
||||||
|
private static final int TAG_GEOM_LINE = 2;
|
||||||
|
private static final int TAG_GEOM_POLYGON = 3;
|
||||||
|
|
||||||
|
//rivate final short[] mTmpKeys = new short[100];
|
||||||
|
//private final Tag[] mTmpTags = new Tag[20];
|
||||||
|
//private Tag[][] mElementTags;
|
||||||
|
|
||||||
|
private short[] mTmpTags = new short[1024];
|
||||||
|
|
||||||
|
//private final short[] mPrevTags = new short[1024];
|
||||||
|
|
||||||
|
private void initDecorder() {
|
||||||
|
// reusable tag set
|
||||||
|
// Tag[][] tags = new Tag[10][];
|
||||||
|
// for (int i = 0; i < 10; i++)
|
||||||
|
// tags[i] = new Tag[i + 1];
|
||||||
|
//mElementTags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decode() throws IOException {
|
||||||
|
|
||||||
|
int val;
|
||||||
|
|
||||||
|
while (lwHttp.hasData() && (val = decodeVarint32()) > 0) {
|
||||||
|
// read tag and wire type
|
||||||
|
int tag = (val >> 3);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_TILE_LAYERS:
|
||||||
|
decodeLayer();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.d(TAG, mTile + " invalid type for tile: " + tag);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decodeLayer() throws IOException {
|
||||||
|
|
||||||
|
int version = 0;
|
||||||
|
int extent = 4096;
|
||||||
|
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
|
ArrayList<String> keys = new ArrayList<String>();
|
||||||
|
ArrayList<String> values = new ArrayList<String>();
|
||||||
|
|
||||||
|
String name = null;
|
||||||
|
int numFeatures = 0;
|
||||||
|
ArrayList<Feature> features = new ArrayList<MapDatabase.Feature>();
|
||||||
|
|
||||||
|
int end = lwHttp.position() + bytes;
|
||||||
|
while (lwHttp.position() < end) {
|
||||||
|
// read tag and wire type
|
||||||
|
int val = decodeVarint32();
|
||||||
|
if (val == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int tag = (val >> 3);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_LAYER_KEYS:
|
||||||
|
keys.add(decodeString());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_LAYER_VALUES:
|
||||||
|
values.add(decodeValue());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_LAYER_FEATURES:
|
||||||
|
numFeatures++;
|
||||||
|
decodeFeature(features);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_LAYER_VERSION:
|
||||||
|
version = decodeVarint32();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_LAYER_NAME:
|
||||||
|
name = decodeString();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_LAYER_EXTENT:
|
||||||
|
extent = decodeVarint32();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.d(TAG, mTile + " invalid type for layer: " + tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
boolean isRoad = "road".equals(name);
|
||||||
|
boolean isBridge = "bridge".equals(name);
|
||||||
|
boolean isTunnel = "tunnel".equals(name);
|
||||||
|
boolean isBuilding = "building".equals(name);
|
||||||
|
boolean isLanduse = "landuse".equals(name);
|
||||||
|
boolean isWater = "water".equals(name);
|
||||||
|
|
||||||
|
Tag layerTag = new Tag(name, Tag.VALUE_YES);
|
||||||
|
|
||||||
|
if (numFeatures == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (Feature f : features) {
|
||||||
|
int addTags = 0;
|
||||||
|
if (isBuilding || isWater)
|
||||||
|
addTags = 1;
|
||||||
|
|
||||||
|
Tag[] tags = new Tag[f.numTags + addTags];
|
||||||
|
|
||||||
|
if (isBuilding)
|
||||||
|
tags[tags.length - 1] = BUILDING_TAG;
|
||||||
|
if (isWater)
|
||||||
|
tags[tags.length - 1] = WATER_TAG;
|
||||||
|
|
||||||
|
if (tags.length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = 0; j < (f.numTags << 1); j += 2) {
|
||||||
|
|
||||||
|
String key = keys.get(f.tags[j]);
|
||||||
|
String val = values.get(f.tags[j + 1]);
|
||||||
|
|
||||||
|
Tag tag = null;
|
||||||
|
if ("class".equals(key)) {
|
||||||
|
if (isRoad || isTunnel || isBridge) {
|
||||||
|
if ("street".equals(val))
|
||||||
|
tag = HIGHWAY_STREET_TAG;
|
||||||
|
else if ("main".equals(val))
|
||||||
|
tag = HIGHWAY_MAIN_TAG;
|
||||||
|
else if ("major".equals(val))
|
||||||
|
tag = HIGHWAY_MAJOR_TAG;
|
||||||
|
else if ("major_rail".equals(val))
|
||||||
|
tag = HIGHWAY_RAIL_TAG;
|
||||||
|
else
|
||||||
|
tag = new Tag(Tag.TAG_KEY_HIGHWAY, val);
|
||||||
|
|
||||||
|
} else if (isLanduse)
|
||||||
|
tag = new Tag(Tag.TAG_KEY_LANDUSE, val);
|
||||||
|
}
|
||||||
|
if (tag == null)
|
||||||
|
tag = new Tag(key, val);
|
||||||
|
|
||||||
|
tags[j >> 1] = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.elem.set(tags, 5);
|
||||||
|
mMapGenerator.renderElement(f.elem);
|
||||||
|
mFeaturePool.release(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Pool<Feature> mFeaturePool = new Pool<Feature>() {
|
||||||
|
int count;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Feature createItem() {
|
||||||
|
count++;
|
||||||
|
return new Feature();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean clearItem(Feature item) {
|
||||||
|
if (count > 50) {
|
||||||
|
count--;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.elem.tags = null;
|
||||||
|
item.elem.clear();
|
||||||
|
item.tags = null;
|
||||||
|
item.type = 0;
|
||||||
|
item.numTags = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final static Tag WATER_TAG = new Tag("natural", "water");
|
||||||
|
private final static Tag BUILDING_TAG = new Tag("building", "yes");
|
||||||
|
private final static Tag HIGHWAY_MAIN_TAG = new Tag("highway", "secondary");
|
||||||
|
private final static Tag HIGHWAY_MAJOR_TAG = new Tag("highway", "primary");
|
||||||
|
private final static Tag HIGHWAY_STREET_TAG = new Tag("highway", "residential");
|
||||||
|
private final static Tag HIGHWAY_RAIL_TAG = new Tag("railway", "rail");
|
||||||
|
|
||||||
|
//private final Tag[] mFallbackTag = new Tag[] { new Tag("debug", "way") };
|
||||||
|
|
||||||
|
// private int mClipped;
|
||||||
|
|
||||||
|
static class Feature extends Inlist<Feature> {
|
||||||
|
short[] tags;
|
||||||
|
int numTags;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
final MapElement elem;
|
||||||
|
|
||||||
|
Feature() {
|
||||||
|
elem = new MapElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean match(short otherTags[], int otherNumTags, int otherType) {
|
||||||
|
if (numTags != otherNumTags)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (type != otherType)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < numTags << 1; i++) {
|
||||||
|
if (tags[i] != otherTags[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decodeFeature(ArrayList<Feature> features) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
int end = lwHttp.position() + bytes;
|
||||||
|
|
||||||
|
int type = 0;
|
||||||
|
long id;
|
||||||
|
|
||||||
|
lastX = 0;
|
||||||
|
lastY = 0;
|
||||||
|
|
||||||
|
mTmpTags[0] = -1;
|
||||||
|
|
||||||
|
Feature curFeature = null;
|
||||||
|
int numTags = 0;
|
||||||
|
|
||||||
|
//Log.d(TAG, "start feature");
|
||||||
|
while (lwHttp.position() < end) {
|
||||||
|
// read tag and wire type
|
||||||
|
int val = decodeVarint32();
|
||||||
|
if (val == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int tag = (val >>> 3);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_FEATURE_ID:
|
||||||
|
id = decodeVarint32();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FEATURE_TAGS:
|
||||||
|
mTmpTags = decodeShortArray(mTmpTags);
|
||||||
|
|
||||||
|
for (; numTags < mTmpTags.length && mTmpTags[numTags] >= 0;)
|
||||||
|
numTags += 2;
|
||||||
|
|
||||||
|
numTags >>= 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FEATURE_TYPE:
|
||||||
|
type = decodeVarint32();
|
||||||
|
|
||||||
|
//Log.d(TAG, "got type " + type);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_FEATURE_GEOMETRY:
|
||||||
|
|
||||||
|
for (Feature f : features) {
|
||||||
|
if (f.match(mTmpTags, numTags, type)) {
|
||||||
|
curFeature = f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curFeature == null) {
|
||||||
|
curFeature = mFeaturePool.get();
|
||||||
|
curFeature.tags = new short[numTags << 1];
|
||||||
|
System.arraycopy(mTmpTags, 0, curFeature.tags, 0, numTags << 1);
|
||||||
|
curFeature.numTags = numTags;
|
||||||
|
curFeature.type = type;
|
||||||
|
|
||||||
|
features.add(curFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeCoordinates(type, curFeature);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.d(TAG, mTile + " invalid type for feature: " + tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static int CLOSE_PATH = 0x07;
|
||||||
|
private final static int MOVE_TO = 0x01;
|
||||||
|
//private final static int LINE_TO = 0x02;
|
||||||
|
|
||||||
|
private int lastX, lastY;
|
||||||
|
private final int pixel = 7;
|
||||||
|
|
||||||
|
private int decodeCoordinates(int type, Feature feature) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
lwHttp.readBuffer(bytes);
|
||||||
|
|
||||||
|
if (feature == null) {
|
||||||
|
lwHttp.bufferPos += bytes;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapElement elem = feature.elem;
|
||||||
|
|
||||||
|
boolean isPoint = false;
|
||||||
|
boolean isPoly = false;
|
||||||
|
boolean isLine = false;
|
||||||
|
|
||||||
|
if (type == TAG_GEOM_LINE) {
|
||||||
|
elem.startLine();
|
||||||
|
isLine = true;
|
||||||
|
}
|
||||||
|
else if (type == TAG_GEOM_POLYGON) {
|
||||||
|
elem.startPolygon();
|
||||||
|
isPoly = true;
|
||||||
|
} else if (type == TAG_GEOM_POINT) {
|
||||||
|
isPoint = true;
|
||||||
|
elem.startPoints();
|
||||||
|
} else if (type == TAG_GEOM_UNKNOWN)
|
||||||
|
elem.startPoints();
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
boolean even = true;
|
||||||
|
|
||||||
|
float scale = mScaleFactor;
|
||||||
|
|
||||||
|
byte[] buf = lwHttp.buffer;
|
||||||
|
int pos = lwHttp.bufferPos;
|
||||||
|
int end = pos + bytes;
|
||||||
|
int val;
|
||||||
|
int curX = 0;
|
||||||
|
int curY = 0;
|
||||||
|
int prevX = 0;
|
||||||
|
int prevY = 0;
|
||||||
|
|
||||||
|
int cmd = 0;
|
||||||
|
int num = 0;
|
||||||
|
boolean first = true;
|
||||||
|
boolean lastClip = false;
|
||||||
|
|
||||||
|
boolean isOuter = true;
|
||||||
|
|
||||||
|
int xmin = Integer.MAX_VALUE, xmax = Integer.MIN_VALUE;
|
||||||
|
int ymin = Integer.MAX_VALUE, ymax = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
|
||||||
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| buf[pos++] << 7;
|
||||||
|
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32 in " + mTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num == 0) {
|
||||||
|
num = val >>> 3;
|
||||||
|
cmd = val & 0x07;
|
||||||
|
|
||||||
|
if (isLine && lastClip) {
|
||||||
|
elem.addPoint(curX / scale, curY / scale);
|
||||||
|
lastClip = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == CLOSE_PATH) {
|
||||||
|
num = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cmd == MOVE_TO) {
|
||||||
|
if (type == TAG_GEOM_LINE)
|
||||||
|
elem.startLine();
|
||||||
|
else if (type == TAG_GEOM_POLYGON) {
|
||||||
|
isOuter = false;
|
||||||
|
elem.startHole();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// zigzag decoding
|
||||||
|
int s = ((val >>> 1) ^ -(val & 1));
|
||||||
|
|
||||||
|
if (even) {
|
||||||
|
even = false;
|
||||||
|
curX = lastX = lastX + s;
|
||||||
|
} else {
|
||||||
|
even = true;
|
||||||
|
|
||||||
|
curY = lastY = lastY + s;
|
||||||
|
|
||||||
|
int dx = (curX - prevX);
|
||||||
|
int dy = (curY - prevY);
|
||||||
|
|
||||||
|
if ((isPoint || cmd == MOVE_TO)
|
||||||
|
|| (dx > pixel || dx < -pixel)
|
||||||
|
|| (dy > pixel || dy < -pixel)
|
||||||
|
// dont clip at tile boundaries
|
||||||
|
|| (curX <= 0 || curX >= 4095)
|
||||||
|
|| (curY <= 0 || curY >= 4095)) {
|
||||||
|
prevX = curX;
|
||||||
|
prevY = curY;
|
||||||
|
elem.addPoint(curX / scale, curY / scale);
|
||||||
|
lastClip = false;
|
||||||
|
|
||||||
|
if (isPoly) {
|
||||||
|
if (curX < xmin)
|
||||||
|
xmin = curX;
|
||||||
|
if (curX > xmax)
|
||||||
|
xmax = curX;
|
||||||
|
|
||||||
|
if (curY < ymin)
|
||||||
|
ymin = curY;
|
||||||
|
if (curY > ymax)
|
||||||
|
ymax = curY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lastClip = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
num--;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPoly && isOuter && !testBBox(xmax - xmin, ymax - ymin)) {
|
||||||
|
//Log.d(TAG, "skip small poly "+ elem.indexPos + " > "
|
||||||
|
// + (xmax - xmin) * (ymax - ymin));
|
||||||
|
elem.pointPos -= elem.index[elem.indexPos];
|
||||||
|
if (elem.indexPos > 0) {
|
||||||
|
elem.indexPos -= 3;
|
||||||
|
elem.index[elem.indexPos + 1] = -1;
|
||||||
|
} else {
|
||||||
|
elem.type = GeometryType.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lwHttp.bufferPos += bytes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLine && lastClip)
|
||||||
|
elem.addPoint(curX / scale, curY / scale);
|
||||||
|
|
||||||
|
lwHttp.bufferPos = pos;
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean testBBox(int dx, int dy) {
|
||||||
|
return dx * dy > 64 * 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String decodeValue() throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
int end = lwHttp.position() + bytes;
|
||||||
|
|
||||||
|
while (lwHttp.position() < end) {
|
||||||
|
// read tag and wire type
|
||||||
|
int val = decodeVarint32();
|
||||||
|
if (val == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int tag = (val >> 3);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_VALUE_STRING:
|
||||||
|
value = decodeString();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_VALUE_UINT:
|
||||||
|
value = String.valueOf(decodeVarint32());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_VALUE_SINT:
|
||||||
|
value = String.valueOf(decodeVarint32());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_VALUE_LONG:
|
||||||
|
value = String.valueOf(decodeVarint32());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_VALUE_FLOAT:
|
||||||
|
value = String.valueOf(decodeFloat());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_VALUE_DOUBLE:
|
||||||
|
value = String.valueOf(decodeDouble());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_VALUE_BOOL:
|
||||||
|
value = decodeBool() ? "yes" : "no";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static int VARINT_LIMIT = 7;
|
||||||
|
private final static int VARINT_MAX = 10;
|
||||||
|
|
||||||
|
private short[] decodeShortArray(short[] array) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
int arrayLength = array.length;
|
||||||
|
|
||||||
|
lwHttp.readBuffer(bytes);
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
byte[] buf = lwHttp.buffer;
|
||||||
|
int pos = lwHttp.bufferPos;
|
||||||
|
int end = pos + bytes;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| buf[pos++] << 7;
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32 in " + mTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arrayLength <= cnt) {
|
||||||
|
arrayLength = cnt + 16;
|
||||||
|
short[] tmp = array;
|
||||||
|
array = new short[arrayLength];
|
||||||
|
System.arraycopy(tmp, 0, array, 0, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
array[cnt++] = (short) val;
|
||||||
|
}
|
||||||
|
|
||||||
|
lwHttp.bufferPos = pos;
|
||||||
|
|
||||||
|
if (arrayLength > cnt)
|
||||||
|
array[cnt] = -1;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int decodeVarint32() throws IOException {
|
||||||
|
if (lwHttp.bufferPos + VARINT_MAX > lwHttp.bufferFill)
|
||||||
|
lwHttp.readBuffer(4096);
|
||||||
|
|
||||||
|
byte[] buf = lwHttp.buffer;
|
||||||
|
int pos = lwHttp.bufferPos;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++]) << 7;
|
||||||
|
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21);
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
// 'Discard upper 32 bits'
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32 in " + mTile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lwHttp.bufferPos = pos;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float decodeFloat() throws IOException {
|
||||||
|
if (lwHttp.bufferPos + 4 > lwHttp.bufferFill)
|
||||||
|
lwHttp.readBuffer(4096);
|
||||||
|
|
||||||
|
byte[] buf = lwHttp.buffer;
|
||||||
|
int pos = lwHttp.bufferPos;
|
||||||
|
|
||||||
|
int val = (buf[pos++] & 0xFF
|
||||||
|
| (buf[pos++] & 0xFF) << 8
|
||||||
|
| (buf[pos++] & 0xFF) << 16
|
||||||
|
| (buf[pos++] & 0xFF) << 24);
|
||||||
|
|
||||||
|
lwHttp.bufferPos += 4;
|
||||||
|
|
||||||
|
return Float.intBitsToFloat(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double decodeDouble() throws IOException {
|
||||||
|
if (lwHttp.bufferPos + 8 > lwHttp.bufferFill)
|
||||||
|
lwHttp.readBuffer(4096);
|
||||||
|
|
||||||
|
byte[] buf = lwHttp.buffer;
|
||||||
|
int pos = lwHttp.bufferPos;
|
||||||
|
|
||||||
|
long val = (buf[pos++] & 0xFF
|
||||||
|
| (buf[pos++] & 0xFF) << 8
|
||||||
|
| (buf[pos++] & 0xFF) << 16
|
||||||
|
| (buf[pos++] & 0xFF) << 24
|
||||||
|
| (buf[pos++] & 0xFF) << 32
|
||||||
|
| (buf[pos++] & 0xFF) << 40
|
||||||
|
| (buf[pos++] & 0xFF) << 48
|
||||||
|
| (buf[pos++] & 0xFF) << 56);
|
||||||
|
|
||||||
|
lwHttp.bufferPos += 8;
|
||||||
|
|
||||||
|
return Double.longBitsToDouble(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decodeBool() throws IOException {
|
||||||
|
if (lwHttp.bufferPos + 1 > lwHttp.bufferFill)
|
||||||
|
lwHttp.readBuffer(4096);
|
||||||
|
|
||||||
|
boolean val = lwHttp.buffer[lwHttp.bufferPos++] != 0;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String decodeString() throws IOException {
|
||||||
|
final int size = decodeVarint32();
|
||||||
|
lwHttp.readBuffer(size);
|
||||||
|
final String result = mStringDecoder.decode(lwHttp.buffer, lwHttp.bufferPos, size);
|
||||||
|
|
||||||
|
//Log.d(TAG, "string: " + result);
|
||||||
|
|
||||||
|
lwHttp.bufferPos += size;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user