Move OsmAnd java core project back to android repository for maintainance reasons
This commit is contained in:
parent
42a239c0f3
commit
7bc162a878
199 changed files with 89973 additions and 2 deletions
16
OsmAnd-java/.classpath
Normal file
16
OsmAnd-java/.classpath
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry excluding="com/OsMoDroid/" kind="src" path="android"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="libs/bsh-core-2.0b4.jar"/>
|
||||
<classpathentry kind="lib" path="libs/bzip2-20090327.jar"/>
|
||||
<classpathentry kind="lib" path="libs/commons-logging-1.1.1.jar"/>
|
||||
<classpathentry kind="lib" path="libs/json-20090211.jar"/>
|
||||
<classpathentry kind="lib" path="libs/junidecode-0.1.jar"/>
|
||||
<classpathentry kind="lib" path="libs/kxml2-2.3.0.jar"/>
|
||||
<classpathentry kind="lib" path="libs/tuprolog.jar"/>
|
||||
<classpathentry kind="lib" path="libs/icu4j-49_1.jar"/>
|
||||
<classpathentry kind="lib" path="libs/gnu-trove-osmand.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
1
OsmAnd-java/.gitignore
vendored
Normal file
1
OsmAnd-java/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
bin
|
30
OsmAnd-java/.project
Normal file
30
OsmAnd-java/.project
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>OsmAnd-java</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>android</name>
|
||||
<type>2</type>
|
||||
<locationURI>OSMAND_TRUNK/android/OsmAnd/gen</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
<variableList>
|
||||
<variable>
|
||||
<name>OSMAND_TRUNK</name>
|
||||
<value>$%7BPARENT-2-PROJECT_LOC%7D</value>
|
||||
</variable>
|
||||
</variableList>
|
||||
</projectDescription>
|
11
OsmAnd-java/.settings/org.eclipse.jdt.core.prefs
Normal file
11
OsmAnd-java/.settings/org.eclipse.jdt.core.prefs
Normal file
|
@ -0,0 +1,11 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
77
OsmAnd-java/build.xml
Normal file
77
OsmAnd-java/build.xml
Normal file
|
@ -0,0 +1,77 @@
|
|||
<!-- build JAR libraty -->
|
||||
<project name="OsmAnd-core" default="build" basedir=".">
|
||||
|
||||
<property file="local.properties" />
|
||||
|
||||
<property name="src.dir" value="java"/>
|
||||
<property name="src.absolute.dir" location="${src.dir}" />
|
||||
<property name="bin.dir" value="bin"/>
|
||||
<property name="bin.absolute.dir" location="${bin.dir}"/>
|
||||
<property name="lib.dir" value="libs"/>
|
||||
<property name="lib.absolute.dir" location="${lib.dir}" />
|
||||
<property name="java.encoding" value="UTF-8" />
|
||||
|
||||
<path id="build.path">
|
||||
<fileset dir="${lib.absolute.dir}">
|
||||
<include name="*.jar"/>
|
||||
</fileset>
|
||||
</path>
|
||||
|
||||
<target name="-dirs">
|
||||
<mkdir dir="${bin.absolute.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="${bin.absolute.dir}"/>
|
||||
<delete file="OsmAnd-core.jar"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="-dirs">
|
||||
<copy todir="${bin.absolute.dir}">
|
||||
<fileset dir="${src.absolute.dir}">
|
||||
<exclude name="**/*.java" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<javac srcdir="${src.absolute.dir}"
|
||||
destdir="${bin.absolute.dir}" encoding="${java.encoding}" classpathref="build.path" debug="on"
|
||||
source="1.6">
|
||||
<include name="**/*.java"/>
|
||||
<exclude name="net/osmand/plus/**"/>
|
||||
</javac>
|
||||
|
||||
</target>
|
||||
|
||||
<target name="native-libs-jar" depends="compile">
|
||||
<exec command="bash collect_libs.sh" failonerror="true"></exec>
|
||||
<antcall target="jar"/>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<manifestclasspath property="lib.list" jarfile="OsmAnd-core.jar">
|
||||
<classpath refid="build.path"/>
|
||||
</manifestclasspath>
|
||||
<echo>list is ${lib.list}</echo>
|
||||
|
||||
<delete file="OsmAnd-core.jar" />
|
||||
<delete file="MANIFEST.MF" />
|
||||
<manifest file="MANIFEST.MF">
|
||||
<attribute name="Built-By" value="${user.name}" />
|
||||
<attribute name="Main-Class" value="net.osmand.swing.OsmExtractionUI" />
|
||||
<attribute name="Class-Path" value="${lib.list}"/>
|
||||
</manifest>
|
||||
|
||||
<jar destfile="OsmAnd-core.jar" manifest="MANIFEST.MF">
|
||||
<fileset dir="${bin.absolute.dir}">
|
||||
<include name="**/*" />
|
||||
</fileset>
|
||||
<fileset dir="${src.absolute.dir}">
|
||||
<include name="**/*.java" />
|
||||
</fileset>
|
||||
</jar>
|
||||
|
||||
<delete file="MANIFEST.MF" />
|
||||
</target>
|
||||
|
||||
<target name="build" depends="jar">
|
||||
</target>
|
||||
</project>
|
BIN
OsmAnd-java/libs/bsh-core-2.0b4.jar
Normal file
BIN
OsmAnd-java/libs/bsh-core-2.0b4.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/bzip2-20090327.jar
Normal file
BIN
OsmAnd-java/libs/bzip2-20090327.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/commons-logging-1.1.1.jar
Normal file
BIN
OsmAnd-java/libs/commons-logging-1.1.1.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/gnu-trove-osmand.jar
Normal file
BIN
OsmAnd-java/libs/gnu-trove-osmand.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/icu4j-49_1.jar
Normal file
BIN
OsmAnd-java/libs/icu4j-49_1.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/json-20090211.jar
Normal file
BIN
OsmAnd-java/libs/json-20090211.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/junidecode-0.1.jar
Normal file
BIN
OsmAnd-java/libs/junidecode-0.1.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/kxml2-2.3.0.jar
Normal file
BIN
OsmAnd-java/libs/kxml2-2.3.0.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/simple-logging.jar
Normal file
BIN
OsmAnd-java/libs/simple-logging.jar
Normal file
Binary file not shown.
BIN
OsmAnd-java/libs/tuprolog.jar
Normal file
BIN
OsmAnd-java/libs/tuprolog.jar
Normal file
Binary file not shown.
714
OsmAnd-java/src/com/google/protobuf/AbstractMessage.java
Normal file
714
OsmAnd-java/src/com/google/protobuf/AbstractMessage.java
Normal file
|
@ -0,0 +1,714 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Message} interface which implements
|
||||
* as many methods of that interface as possible in terms of other methods.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class AbstractMessage extends AbstractMessageLite
|
||||
implements Message {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean isInitialized() {
|
||||
// Check that all required fields are present.
|
||||
for (final FieldDescriptor field : getDescriptorForType().getFields()) {
|
||||
if (field.isRequired()) {
|
||||
if (!hasField(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that embedded messages are initialized.
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
getAllFields().entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (field.isRepeated()) {
|
||||
for (final Message element : (List<Message>) entry.getValue()) {
|
||||
if (!element.isInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!((Message) entry.getValue()).isInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return TextFormat.printToString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final CodedOutputStream output) throws IOException {
|
||||
final boolean isMessageSet =
|
||||
getDescriptorForType().getOptions().getMessageSetWireFormat();
|
||||
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
getAllFields().entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
if (isMessageSet && field.isExtension() &&
|
||||
field.getType() == FieldDescriptor.Type.MESSAGE &&
|
||||
!field.isRepeated()) {
|
||||
output.writeMessageSetExtension(field.getNumber(), (Message) value);
|
||||
} else {
|
||||
FieldSet.writeField(field, value, output);
|
||||
}
|
||||
}
|
||||
|
||||
final UnknownFieldSet unknownFields = getUnknownFields();
|
||||
if (isMessageSet) {
|
||||
unknownFields.writeAsMessageSetTo(output);
|
||||
} else {
|
||||
unknownFields.writeTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
private int memoizedSize = -1;
|
||||
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSize;
|
||||
if (size != -1) {
|
||||
return size;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
final boolean isMessageSet =
|
||||
getDescriptorForType().getOptions().getMessageSetWireFormat();
|
||||
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
getAllFields().entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
if (isMessageSet && field.isExtension() &&
|
||||
field.getType() == FieldDescriptor.Type.MESSAGE &&
|
||||
!field.isRepeated()) {
|
||||
size += CodedOutputStream.computeMessageSetExtensionSize(
|
||||
field.getNumber(), (Message) value);
|
||||
} else {
|
||||
size += FieldSet.computeFieldSize(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
final UnknownFieldSet unknownFields = getUnknownFields();
|
||||
if (isMessageSet) {
|
||||
size += unknownFields.getSerializedSizeAsMessageSet();
|
||||
} else {
|
||||
size += unknownFields.getSerializedSize();
|
||||
}
|
||||
|
||||
memoizedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof Message)) {
|
||||
return false;
|
||||
}
|
||||
final Message otherMessage = (Message) other;
|
||||
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
|
||||
return false;
|
||||
}
|
||||
return getAllFields().equals(otherMessage.getAllFields()) &&
|
||||
getUnknownFields().equals(otherMessage.getUnknownFields());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 41;
|
||||
hash = (19 * hash) + getDescriptorForType().hashCode();
|
||||
hash = (53 * hash) + getAllFields().hashCode();
|
||||
hash = (29 * hash) + getUnknownFields().hashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Message.Builder} interface which
|
||||
* implements as many methods of that interface as possible in terms of
|
||||
* other methods.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static abstract class Builder<BuilderType extends Builder>
|
||||
extends AbstractMessageLite.Builder<BuilderType>
|
||||
implements Message.Builder {
|
||||
// The compiler produces an error if this is not declared explicitly.
|
||||
@Override
|
||||
public abstract BuilderType clone();
|
||||
|
||||
@Override
|
||||
public BuilderType clear() {
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
getAllFields().entrySet()) {
|
||||
clearField(entry.getKey());
|
||||
}
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final Message other) {
|
||||
if (other.getDescriptorForType() != getDescriptorForType()) {
|
||||
throw new IllegalArgumentException(
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
}
|
||||
|
||||
// Note: We don't attempt to verify that other's fields have valid
|
||||
// types. Doing so would be a losing battle. We'd have to verify
|
||||
// all sub-messages as well, and we'd have to make copies of all of
|
||||
// them to insure that they don't change after verification (since
|
||||
// the Message interface itself cannot enforce immutability of
|
||||
// implementations).
|
||||
// TODO(kenton): Provide a function somewhere called makeDeepCopy()
|
||||
// which allows people to make secure deep copies of messages.
|
||||
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
other.getAllFields().entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
if (field.isRepeated()) {
|
||||
for (final Object element : (List)entry.getValue()) {
|
||||
addRepeatedField(field, element);
|
||||
}
|
||||
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
final Message existingValue = (Message)getField(field);
|
||||
if (existingValue == existingValue.getDefaultInstanceForType()) {
|
||||
setField(field, entry.getValue());
|
||||
} else {
|
||||
setField(field,
|
||||
existingValue.newBuilderForType()
|
||||
.mergeFrom(existingValue)
|
||||
.mergeFrom((Message)entry.getValue())
|
||||
.build());
|
||||
}
|
||||
} else {
|
||||
setField(field, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
mergeUnknownFields(other.getUnknownFields());
|
||||
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final CodedInputStream input)
|
||||
throws IOException {
|
||||
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final CodedInputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
final UnknownFieldSet.Builder unknownFields =
|
||||
UnknownFieldSet.newBuilder(getUnknownFields());
|
||||
while (true) {
|
||||
final int tag = input.readTag();
|
||||
if (tag == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
|
||||
this, tag)) {
|
||||
// end group tag
|
||||
break;
|
||||
}
|
||||
}
|
||||
setUnknownFields(unknownFields.build());
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
|
||||
* ExtensionRegistryLite, Message.Builder)}, but parses a single field.
|
||||
* Package-private because it is used by GeneratedMessage.ExtendableMessage.
|
||||
* @param tag The tag, which should have already been read.
|
||||
* @return {@code true} unless the tag is an end-group tag.
|
||||
*/
|
||||
static boolean mergeFieldFrom(
|
||||
final CodedInputStream input,
|
||||
final UnknownFieldSet.Builder unknownFields,
|
||||
final ExtensionRegistryLite extensionRegistry,
|
||||
final Message.Builder builder,
|
||||
final int tag) throws IOException {
|
||||
final Descriptor type = builder.getDescriptorForType();
|
||||
|
||||
if (type.getOptions().getMessageSetWireFormat() &&
|
||||
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
|
||||
mergeMessageSetExtensionFromCodedStream(
|
||||
input, unknownFields, extensionRegistry, builder);
|
||||
return true;
|
||||
}
|
||||
|
||||
final int wireType = WireFormat.getTagWireType(tag);
|
||||
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
|
||||
|
||||
final FieldDescriptor field;
|
||||
Message defaultInstance = null;
|
||||
|
||||
if (type.isExtensionNumber(fieldNumber)) {
|
||||
// extensionRegistry may be either ExtensionRegistry or
|
||||
// ExtensionRegistryLite. Since the type we are parsing is a full
|
||||
// message, only a full ExtensionRegistry could possibly contain
|
||||
// extensions of it. Otherwise we will treat the registry as if it
|
||||
// were empty.
|
||||
if (extensionRegistry instanceof ExtensionRegistry) {
|
||||
final ExtensionRegistry.ExtensionInfo extension =
|
||||
((ExtensionRegistry) extensionRegistry)
|
||||
.findExtensionByNumber(type, fieldNumber);
|
||||
if (extension == null) {
|
||||
field = null;
|
||||
} else {
|
||||
field = extension.descriptor;
|
||||
defaultInstance = extension.defaultInstance;
|
||||
if (defaultInstance == null &&
|
||||
field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalStateException(
|
||||
"Message-typed extension lacked default instance: " +
|
||||
field.getFullName());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field = null;
|
||||
}
|
||||
} else {
|
||||
field = type.findFieldByNumber(fieldNumber);
|
||||
}
|
||||
|
||||
boolean unknown = false;
|
||||
boolean packed = false;
|
||||
if (field == null) {
|
||||
unknown = true; // Unknown field.
|
||||
} else if (wireType == FieldSet.getWireFormatForFieldType(
|
||||
field.getLiteType(),
|
||||
false /* isPacked */)) {
|
||||
packed = false;
|
||||
} else if (field.isPackable() &&
|
||||
wireType == FieldSet.getWireFormatForFieldType(
|
||||
field.getLiteType(),
|
||||
true /* isPacked */)) {
|
||||
packed = true;
|
||||
} else {
|
||||
unknown = true; // Unknown wire type.
|
||||
}
|
||||
|
||||
if (unknown) { // Unknown field or wrong wire type. Skip.
|
||||
return unknownFields.mergeFieldFrom(tag, input);
|
||||
}
|
||||
|
||||
if (packed) {
|
||||
final int length = input.readRawVarint32();
|
||||
final int limit = input.pushLimit(length);
|
||||
if (field.getLiteType() == WireFormat.FieldType.ENUM) {
|
||||
while (input.getBytesUntilLimit() > 0) {
|
||||
final int rawValue = input.readEnum();
|
||||
final Object value = field.getEnumType().findValueByNumber(rawValue);
|
||||
if (value == null) {
|
||||
// If the number isn't recognized as a valid value for this
|
||||
// enum, drop it (don't even add it to unknownFields).
|
||||
return true;
|
||||
}
|
||||
builder.addRepeatedField(field, value);
|
||||
}
|
||||
} else {
|
||||
while (input.getBytesUntilLimit() > 0) {
|
||||
final Object value =
|
||||
FieldSet.readPrimitiveField(input, field.getLiteType());
|
||||
builder.addRepeatedField(field, value);
|
||||
}
|
||||
}
|
||||
input.popLimit(limit);
|
||||
} else {
|
||||
final Object value;
|
||||
switch (field.getType()) {
|
||||
case GROUP: {
|
||||
final Message.Builder subBuilder;
|
||||
if (defaultInstance != null) {
|
||||
subBuilder = defaultInstance.newBuilderForType();
|
||||
} else {
|
||||
subBuilder = builder.newBuilderForField(field);
|
||||
}
|
||||
if (!field.isRepeated()) {
|
||||
subBuilder.mergeFrom((Message) builder.getField(field));
|
||||
}
|
||||
input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
|
||||
value = subBuilder.build();
|
||||
break;
|
||||
}
|
||||
case MESSAGE: {
|
||||
final Message.Builder subBuilder;
|
||||
if (defaultInstance != null) {
|
||||
subBuilder = defaultInstance.newBuilderForType();
|
||||
} else {
|
||||
subBuilder = builder.newBuilderForField(field);
|
||||
}
|
||||
if (!field.isRepeated()) {
|
||||
subBuilder.mergeFrom((Message) builder.getField(field));
|
||||
}
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
value = subBuilder.build();
|
||||
break;
|
||||
}
|
||||
case ENUM:
|
||||
final int rawValue = input.readEnum();
|
||||
value = field.getEnumType().findValueByNumber(rawValue);
|
||||
// If the number isn't recognized as a valid value for this enum,
|
||||
// drop it.
|
||||
if (value == null) {
|
||||
unknownFields.mergeVarintField(fieldNumber, rawValue);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
value = FieldSet.readPrimitiveField(input, field.getLiteType());
|
||||
break;
|
||||
}
|
||||
|
||||
if (field.isRepeated()) {
|
||||
builder.addRepeatedField(field, value);
|
||||
} else {
|
||||
builder.setField(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
|
||||
private static void mergeMessageSetExtensionFromCodedStream(
|
||||
final CodedInputStream input,
|
||||
final UnknownFieldSet.Builder unknownFields,
|
||||
final ExtensionRegistryLite extensionRegistry,
|
||||
final Message.Builder builder) throws IOException {
|
||||
final Descriptor type = builder.getDescriptorForType();
|
||||
|
||||
// The wire format for MessageSet is:
|
||||
// message MessageSet {
|
||||
// repeated group Item = 1 {
|
||||
// required int32 typeId = 2;
|
||||
// required bytes message = 3;
|
||||
// }
|
||||
// }
|
||||
// "typeId" is the extension's field number. The extension can only be
|
||||
// a message type, where "message" contains the encoded bytes of that
|
||||
// message.
|
||||
//
|
||||
// In practice, we will probably never see a MessageSet item in which
|
||||
// the message appears before the type ID, or where either field does not
|
||||
// appear exactly once. However, in theory such cases are valid, so we
|
||||
// should be prepared to accept them.
|
||||
|
||||
int typeId = 0;
|
||||
ByteString rawBytes = null; // If we encounter "message" before "typeId"
|
||||
Message.Builder subBuilder = null;
|
||||
FieldDescriptor field = null;
|
||||
|
||||
while (true) {
|
||||
final int tag = input.readTag();
|
||||
if (tag == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
|
||||
typeId = input.readUInt32();
|
||||
// Zero is not a valid type ID.
|
||||
if (typeId != 0) {
|
||||
final ExtensionRegistry.ExtensionInfo extension;
|
||||
|
||||
// extensionRegistry may be either ExtensionRegistry or
|
||||
// ExtensionRegistryLite. Since the type we are parsing is a full
|
||||
// message, only a full ExtensionRegistry could possibly contain
|
||||
// extensions of it. Otherwise we will treat the registry as if it
|
||||
// were empty.
|
||||
if (extensionRegistry instanceof ExtensionRegistry) {
|
||||
extension = ((ExtensionRegistry) extensionRegistry)
|
||||
.findExtensionByNumber(type, typeId);
|
||||
} else {
|
||||
extension = null;
|
||||
}
|
||||
|
||||
if (extension != null) {
|
||||
field = extension.descriptor;
|
||||
subBuilder = extension.defaultInstance.newBuilderForType();
|
||||
final Message originalMessage = (Message)builder.getField(field);
|
||||
if (originalMessage != null) {
|
||||
subBuilder.mergeFrom(originalMessage);
|
||||
}
|
||||
if (rawBytes != null) {
|
||||
// We already encountered the message. Parse it now.
|
||||
subBuilder.mergeFrom(
|
||||
CodedInputStream.newInstance(rawBytes.newInput()));
|
||||
rawBytes = null;
|
||||
}
|
||||
} else {
|
||||
// Unknown extension number. If we already saw data, put it
|
||||
// in rawBytes.
|
||||
if (rawBytes != null) {
|
||||
unknownFields.mergeField(typeId,
|
||||
UnknownFieldSet.Field.newBuilder()
|
||||
.addLengthDelimited(rawBytes)
|
||||
.build());
|
||||
rawBytes = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
|
||||
if (typeId == 0) {
|
||||
// We haven't seen a type ID yet, so we have to store the raw bytes
|
||||
// for now.
|
||||
rawBytes = input.readBytes();
|
||||
} else if (subBuilder == null) {
|
||||
// We don't know how to parse this. Ignore it.
|
||||
unknownFields.mergeField(typeId,
|
||||
UnknownFieldSet.Field.newBuilder()
|
||||
.addLengthDelimited(input.readBytes())
|
||||
.build());
|
||||
} else {
|
||||
// We already know the type, so we can parse directly from the input
|
||||
// with no copying. Hooray!
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
}
|
||||
} else {
|
||||
// Unknown tag. Skip it.
|
||||
if (!input.skipField(tag)) {
|
||||
break; // end of group
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
|
||||
|
||||
if (subBuilder != null) {
|
||||
builder.setField(field, subBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
|
||||
setUnknownFields(
|
||||
UnknownFieldSet.newBuilder(getUnknownFields())
|
||||
.mergeFrom(unknownFields)
|
||||
.build());
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an UninitializedMessageException reporting missing fields in
|
||||
* the given message.
|
||||
*/
|
||||
protected static UninitializedMessageException
|
||||
newUninitializedMessageException(Message message) {
|
||||
return new UninitializedMessageException(findMissingFields(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates {@code this.missingFields} with the full "path" of each
|
||||
* missing required field in the given message.
|
||||
*/
|
||||
private static List<String> findMissingFields(final Message message) {
|
||||
final List<String> results = new ArrayList<String>();
|
||||
findMissingFields(message, "", results);
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Recursive helper implementing {@link #findMissingFields(Message)}. */
|
||||
private static void findMissingFields(final Message message,
|
||||
final String prefix,
|
||||
final List<String> results) {
|
||||
for (final FieldDescriptor field :
|
||||
message.getDescriptorForType().getFields()) {
|
||||
if (field.isRequired() && !message.hasField(field)) {
|
||||
results.add(prefix + field.getName());
|
||||
}
|
||||
}
|
||||
|
||||
for (final Map.Entry<FieldDescriptor, Object> entry :
|
||||
message.getAllFields().entrySet()) {
|
||||
final FieldDescriptor field = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (field.isRepeated()) {
|
||||
int i = 0;
|
||||
for (final Object element : (List) value) {
|
||||
findMissingFields((Message) element,
|
||||
subMessagePrefix(prefix, field, i++),
|
||||
results);
|
||||
}
|
||||
} else {
|
||||
if (message.hasField(field)) {
|
||||
findMissingFields((Message) value,
|
||||
subMessagePrefix(prefix, field, -1),
|
||||
results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String subMessagePrefix(final String prefix,
|
||||
final FieldDescriptor field,
|
||||
final int index) {
|
||||
final StringBuilder result = new StringBuilder(prefix);
|
||||
if (field.isExtension()) {
|
||||
result.append('(')
|
||||
.append(field.getFullName())
|
||||
.append(')');
|
||||
} else {
|
||||
result.append(field.getName());
|
||||
}
|
||||
if (index != -1) {
|
||||
result.append('[')
|
||||
.append(index)
|
||||
.append(']');
|
||||
}
|
||||
result.append('.');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// The following definitions seem to be required in order to make javac
|
||||
// not produce weird errors like:
|
||||
//
|
||||
// java/com/google/protobuf/DynamicMessage.java:203: types
|
||||
// com.google.protobuf.AbstractMessage.Builder<
|
||||
// com.google.protobuf.DynamicMessage.Builder> and
|
||||
// com.google.protobuf.AbstractMessage.Builder<
|
||||
// com.google.protobuf.DynamicMessage.Builder> are incompatible; both
|
||||
// define mergeFrom(com.google.protobuf.ByteString), but with unrelated
|
||||
// return types.
|
||||
//
|
||||
// Strangely, these lines are only needed if javac is invoked separately
|
||||
// on AbstractMessage.java and AbstractMessageLite.java. If javac is
|
||||
// invoked on both simultaneously, it works. (Or maybe the important
|
||||
// point is whether or not DynamicMessage.java is compiled together with
|
||||
// AbstractMessageLite.java -- not sure.) I suspect this is a compiler
|
||||
// bug.
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return super.mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final ByteString data,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return super.mergeFrom(data, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return super.mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data, final int off, final int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
return super.mergeFrom(data, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return super.mergeFrom(data, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data, final int off, final int len,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return super.mergeFrom(data, off, len, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final InputStream input)
|
||||
throws IOException {
|
||||
return super.mergeFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final InputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
return super.mergeFrom(input, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(final InputStream input)
|
||||
throws IOException {
|
||||
return super.mergeDelimitedFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(
|
||||
final InputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
return super.mergeDelimitedFrom(input, extensionRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
342
OsmAnd-java/src/com/google/protobuf/AbstractMessageLite.java
Normal file
342
OsmAnd-java/src/com/google/protobuf/AbstractMessageLite.java
Normal file
|
@ -0,0 +1,342 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link MessageLite} interface which
|
||||
* implements as many methods of that interface as possible in terms of other
|
||||
* methods.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class AbstractMessageLite implements MessageLite {
|
||||
@Override
|
||||
public ByteString toByteString() {
|
||||
try {
|
||||
final ByteString.CodedBuilder out =
|
||||
ByteString.newCodedBuilder(getSerializedSize());
|
||||
writeTo(out.getCodedOutput());
|
||||
return out.build();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Serializing to a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
try {
|
||||
final byte[] result = new byte[getSerializedSize()];
|
||||
final CodedOutputStream output = CodedOutputStream.newInstance(result);
|
||||
writeTo(output);
|
||||
output.checkNoSpaceLeft();
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Serializing to a byte array threw an IOException " +
|
||||
"(should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(final OutputStream output) throws IOException {
|
||||
final int bufferSize =
|
||||
CodedOutputStream.computePreferredBufferSize(getSerializedSize());
|
||||
final CodedOutputStream codedOutput =
|
||||
CodedOutputStream.newInstance(output, bufferSize);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDelimitedTo(final OutputStream output) throws IOException {
|
||||
final int serialized = getSerializedSize();
|
||||
final int bufferSize = CodedOutputStream.computePreferredBufferSize(
|
||||
CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
|
||||
final CodedOutputStream codedOutput =
|
||||
CodedOutputStream.newInstance(output, bufferSize);
|
||||
codedOutput.writeRawVarint32(serialized);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Message.Builder} interface which
|
||||
* implements as many methods of that interface as possible in terms of
|
||||
* other methods.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static abstract class Builder<BuilderType extends Builder>
|
||||
implements MessageLite.Builder {
|
||||
// The compiler produces an error if this is not declared explicitly.
|
||||
@Override
|
||||
public abstract BuilderType clone();
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final CodedInputStream input)
|
||||
throws IOException {
|
||||
return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
// Re-defined here for return type covariance.
|
||||
@Override
|
||||
public abstract BuilderType mergeFrom(
|
||||
final CodedInputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = data.newCodedInput();
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final ByteString data,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = data.newCodedInput();
|
||||
mergeFrom(input, extensionRegistry);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return mergeFrom(data, 0, data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final byte[] data, final int off,
|
||||
final int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input =
|
||||
CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a byte array threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return mergeFrom(data, 0, data.length, extensionRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final byte[] data, final int off, final int len,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input =
|
||||
CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input, extensionRegistry);
|
||||
input.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a byte array threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(final InputStream input) throws IOException {
|
||||
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
||||
mergeFrom(codedInput);
|
||||
codedInput.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderType mergeFrom(
|
||||
final InputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
||||
mergeFrom(codedInput, extensionRegistry);
|
||||
codedInput.checkLastTagWas(0);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An InputStream implementations which reads from some other InputStream
|
||||
* but is limited to a particular number of bytes. Used by
|
||||
* mergeDelimitedFrom(). This is intentionally package-private so that
|
||||
* UnknownFieldSet can share it.
|
||||
*/
|
||||
static final class LimitedInputStream extends FilterInputStream {
|
||||
private int limit;
|
||||
|
||||
LimitedInputStream(InputStream in, int limit) {
|
||||
super(in);
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return Math.min(super.available(), limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (limit <= 0) {
|
||||
return -1;
|
||||
}
|
||||
final int result = super.read();
|
||||
if (result >= 0) {
|
||||
--limit;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] b, final int off, int len)
|
||||
throws IOException {
|
||||
if (limit <= 0) {
|
||||
return -1;
|
||||
}
|
||||
len = Math.min(len, limit);
|
||||
final int result = super.read(b, off, len);
|
||||
if (result >= 0) {
|
||||
limit -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(final long n) throws IOException {
|
||||
final long result = super.skip(Math.min(n, limit));
|
||||
if (result >= 0) {
|
||||
limit -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(
|
||||
final InputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
final int firstByte = input.read();
|
||||
if (firstByte == -1) {
|
||||
return false;
|
||||
}
|
||||
final int size = CodedInputStream.readRawVarint32(firstByte, input);
|
||||
final InputStream limitedInput = new LimitedInputStream(input, size);
|
||||
mergeFrom(limitedInput, extensionRegistry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(final InputStream input)
|
||||
throws IOException {
|
||||
return mergeDelimitedFrom(input,
|
||||
ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an UninitializedMessageException reporting missing fields in
|
||||
* the given message.
|
||||
*/
|
||||
protected static UninitializedMessageException
|
||||
newUninitializedMessageException(MessageLite message) {
|
||||
return new UninitializedMessageException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the {@code values} to the {@code list}. This is a helper method
|
||||
* used by generated code. Users should ignore it.
|
||||
*
|
||||
* @throws NullPointerException if any of the elements of {@code values} is
|
||||
* null.
|
||||
*/
|
||||
protected static <T> void addAll(final Iterable<T> values,
|
||||
final Collection<? super T> list) {
|
||||
for (final T value : values) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
if (values instanceof Collection) {
|
||||
final
|
||||
Collection<T> collection = (Collection<T>) values;
|
||||
list.addAll(collection);
|
||||
} else {
|
||||
for (final T value : values) {
|
||||
list.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
OsmAnd-java/src/com/google/protobuf/BlockingRpcChannel.java
Normal file
51
OsmAnd-java/src/com/google/protobuf/BlockingRpcChannel.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* <p>Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel}
|
||||
* is the blocking equivalent to {@link RpcChannel}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
* @author cpovirk@google.com Chris Povirk
|
||||
*/
|
||||
public interface BlockingRpcChannel {
|
||||
/**
|
||||
* Call the given method of the remote service and blocks until it returns.
|
||||
* {@code callBlockingMethod()} is the blocking equivalent to
|
||||
* {@link RpcChannel#callMethod}.
|
||||
*/
|
||||
Message callBlockingMethod(
|
||||
Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
Message responsePrototype) throws ServiceException;
|
||||
}
|
64
OsmAnd-java/src/com/google/protobuf/BlockingService.java
Normal file
64
OsmAnd-java/src/com/google/protobuf/BlockingService.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Blocking equivalent to {@link Service}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
* @author cpovirk@google.com Chris Povirk
|
||||
*/
|
||||
public interface BlockingService {
|
||||
/**
|
||||
* Equivalent to {@link Service#getDescriptorForType}.
|
||||
*/
|
||||
Descriptors.ServiceDescriptor getDescriptorForType();
|
||||
|
||||
/**
|
||||
* Equivalent to {@link Service#callMethod}, except that
|
||||
* {@code callBlockingMethod()} returns the result of the RPC or throws a
|
||||
* {@link ServiceException} if there is a failure, rather than passing the
|
||||
* information to a callback.
|
||||
*/
|
||||
Message callBlockingMethod(Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request) throws ServiceException;
|
||||
|
||||
/**
|
||||
* Equivalent to {@link Service#getRequestPrototype}.
|
||||
*/
|
||||
Message getRequestPrototype(Descriptors.MethodDescriptor method);
|
||||
|
||||
/**
|
||||
* Equivalent to {@link Service#getResponsePrototype}.
|
||||
*/
|
||||
Message getResponsePrototype(Descriptors.MethodDescriptor method);
|
||||
}
|
391
OsmAnd-java/src/com/google/protobuf/ByteString.java
Normal file
391
OsmAnd-java/src/com/google/protobuf/ByteString.java
Normal file
|
@ -0,0 +1,391 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Immutable array of bytes.
|
||||
*
|
||||
* @author crazybob@google.com Bob Lee
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class ByteString {
|
||||
private final byte[] bytes;
|
||||
|
||||
private ByteString(final byte[] bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the byte at the given index.
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
|
||||
*/
|
||||
public byte byteAt(final int index) {
|
||||
return bytes[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bytes.
|
||||
*/
|
||||
public int size() {
|
||||
return bytes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return bytes.length == 0;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// byte[] -> ByteString
|
||||
|
||||
/**
|
||||
* Empty ByteString.
|
||||
*/
|
||||
public static final ByteString EMPTY = new ByteString(new byte[0]);
|
||||
|
||||
/**
|
||||
* Copies the given bytes into a {@code ByteString}.
|
||||
*/
|
||||
public static ByteString copyFrom(final byte[] bytes, final int offset,
|
||||
final int size) {
|
||||
final byte[] copy = new byte[size];
|
||||
System.arraycopy(bytes, offset, copy, 0, size);
|
||||
return new ByteString(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the given bytes into a {@code ByteString}.
|
||||
*/
|
||||
public static ByteString copyFrom(final byte[] bytes) {
|
||||
return copyFrom(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies {@code size} bytes from a {@code java.nio.ByteBuffer} into
|
||||
* a {@code ByteString}.
|
||||
*/
|
||||
public static ByteString copyFrom(final ByteBuffer bytes, final int size) {
|
||||
final byte[] copy = new byte[size];
|
||||
bytes.get(copy);
|
||||
return new ByteString(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the remaining bytes from a {@code java.nio.ByteBuffer} into
|
||||
* a {@code ByteString}.
|
||||
*/
|
||||
public static ByteString copyFrom(final ByteBuffer bytes) {
|
||||
return copyFrom(bytes, bytes.remaining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes {@code text} into a sequence of bytes using the named charset
|
||||
* and returns the result as a {@code ByteString}.
|
||||
*/
|
||||
public static ByteString copyFrom(final String text, final String charsetName)
|
||||
throws UnsupportedEncodingException {
|
||||
return new ByteString(text.getBytes(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes {@code text} into a sequence of UTF-8 bytes and returns the
|
||||
* result as a {@code ByteString}.
|
||||
*/
|
||||
public static ByteString copyFromUtf8(final String text) {
|
||||
try {
|
||||
return new ByteString(text.getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("UTF-8 not supported?", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates all byte strings in the list and returns the result.
|
||||
*
|
||||
* <p>The returned {@code ByteString} is not necessarily a unique object.
|
||||
* If the list is empty, the returned object is the singleton empty
|
||||
* {@code ByteString}. If the list has only one element, that
|
||||
* {@code ByteString} will be returned without copying.
|
||||
*/
|
||||
public static ByteString copyFrom(List<ByteString> list) {
|
||||
if (list.size() == 0) {
|
||||
return EMPTY;
|
||||
} else if (list.size() == 1) {
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
for (ByteString str : list) {
|
||||
size += str.size();
|
||||
}
|
||||
byte[] bytes = new byte[size];
|
||||
int pos = 0;
|
||||
for (ByteString str : list) {
|
||||
System.arraycopy(str.bytes, 0, bytes, pos, str.size());
|
||||
pos += str.size();
|
||||
}
|
||||
return new ByteString(bytes);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// ByteString -> byte[]
|
||||
|
||||
/**
|
||||
* Copies bytes into a buffer at the given offset.
|
||||
*
|
||||
* @param target buffer to copy into
|
||||
* @param offset in the target buffer
|
||||
*/
|
||||
public void copyTo(final byte[] target, final int offset) {
|
||||
System.arraycopy(bytes, 0, target, offset, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies bytes into a buffer.
|
||||
*
|
||||
* @param target buffer to copy into
|
||||
* @param sourceOffset offset within these bytes
|
||||
* @param targetOffset offset within the target buffer
|
||||
* @param size number of bytes to copy
|
||||
*/
|
||||
public void copyTo(final byte[] target, final int sourceOffset,
|
||||
final int targetOffset,
|
||||
final int size) {
|
||||
System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies bytes to a {@code byte[]}.
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
final int size = bytes.length;
|
||||
final byte[] copy = new byte[size];
|
||||
System.arraycopy(bytes, 0, copy, 0, size);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new read-only {@code java.nio.ByteBuffer} with the
|
||||
* same backing byte array.
|
||||
*/
|
||||
public ByteBuffer asReadOnlyByteBuffer() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
|
||||
return byteBuffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code String} by decoding the bytes using the
|
||||
* specified charset.
|
||||
*/
|
||||
public String toString(final String charsetName)
|
||||
throws UnsupportedEncodingException {
|
||||
return new String(bytes, charsetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code String} by decoding the bytes as UTF-8.
|
||||
*/
|
||||
public String toStringUtf8() {
|
||||
try {
|
||||
return new String(bytes, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("UTF-8 not supported?", e);
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// equals() and hashCode()
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof ByteString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ByteString other = (ByteString) o;
|
||||
final int size = bytes.length;
|
||||
if (size != other.bytes.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final byte[] thisBytes = bytes;
|
||||
final byte[] otherBytes = other.bytes;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (thisBytes[i] != otherBytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private volatile int hash = 0;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = hash;
|
||||
|
||||
if (h == 0) {
|
||||
final byte[] thisBytes = bytes;
|
||||
final int size = bytes.length;
|
||||
|
||||
h = size;
|
||||
for (int i = 0; i < size; i++) {
|
||||
h = h * 31 + thisBytes[i];
|
||||
}
|
||||
if (h == 0) {
|
||||
h = 1;
|
||||
}
|
||||
|
||||
hash = h;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Input stream
|
||||
|
||||
/**
|
||||
* Creates an {@code InputStream} which can be used to read the bytes.
|
||||
*/
|
||||
public InputStream newInput() {
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CodedInputStream} which can be used to read the bytes.
|
||||
* Using this is more efficient than creating a {@link CodedInputStream}
|
||||
* wrapping the result of {@link #newInput()}.
|
||||
*/
|
||||
public CodedInputStream newCodedInput() {
|
||||
// We trust CodedInputStream not to modify the bytes, or to give anyone
|
||||
// else access to them.
|
||||
return CodedInputStream.newInstance(bytes);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Output stream
|
||||
|
||||
/**
|
||||
* Creates a new {@link Output} with the given initial capacity.
|
||||
*/
|
||||
public static Output newOutput(final int initialCapacity) {
|
||||
return new Output(new ByteArrayOutputStream(initialCapacity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Output}.
|
||||
*/
|
||||
public static Output newOutput() {
|
||||
return newOutput(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
|
||||
* create the {@code ByteString} instance.
|
||||
*/
|
||||
public static final class Output extends FilterOutputStream {
|
||||
private final ByteArrayOutputStream bout;
|
||||
|
||||
/**
|
||||
* Constructs a new output with the given initial capacity.
|
||||
*/
|
||||
private Output(final ByteArrayOutputStream bout) {
|
||||
super(bout);
|
||||
this.bout = bout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ByteString} instance from this {@code Output}.
|
||||
*/
|
||||
public ByteString toByteString() {
|
||||
final byte[] byteArray = bout.toByteArray();
|
||||
return new ByteString(byteArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ByteString builder, which allows you to efficiently
|
||||
* construct a {@code ByteString} by writing to a {@link CodedOutputStream}.
|
||||
* Using this is much more efficient than calling {@code newOutput()} and
|
||||
* wrapping that in a {@code CodedOutputStream}.
|
||||
*
|
||||
* <p>This is package-private because it's a somewhat confusing interface.
|
||||
* Users can call {@link Message#toByteString()} instead of calling this
|
||||
* directly.
|
||||
*
|
||||
* @param size The target byte size of the {@code ByteString}. You must
|
||||
* write exactly this many bytes before building the result.
|
||||
*/
|
||||
static CodedBuilder newCodedBuilder(final int size) {
|
||||
return new CodedBuilder(size);
|
||||
}
|
||||
|
||||
/** See {@link ByteString#newCodedBuilder(int)}. */
|
||||
static final class CodedBuilder {
|
||||
private final CodedOutputStream output;
|
||||
private final byte[] buffer;
|
||||
|
||||
private CodedBuilder(final int size) {
|
||||
buffer = new byte[size];
|
||||
output = CodedOutputStream.newInstance(buffer);
|
||||
}
|
||||
|
||||
public ByteString build() {
|
||||
output.checkNoSpaceLeft();
|
||||
|
||||
// We can be confident that the CodedOutputStream will not modify the
|
||||
// underlying bytes anymore because it already wrote all of them. So,
|
||||
// no need to make a copy.
|
||||
return new ByteString(buffer);
|
||||
}
|
||||
|
||||
public CodedOutputStream getCodedOutput() {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
924
OsmAnd-java/src/com/google/protobuf/CodedInputStream.java
Normal file
924
OsmAnd-java/src/com/google/protobuf/CodedInputStream.java
Normal file
|
@ -0,0 +1,924 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reads and decodes protocol message fields.
|
||||
*
|
||||
* This class contains two kinds of methods: methods that read specific
|
||||
* protocol message constructs and field types (e.g. {@link #readTag()} and
|
||||
* {@link #readInt32()}) and methods that read low-level values (e.g.
|
||||
* {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
|
||||
* encoded protocol messages, you should use the former methods, but if you are
|
||||
* reading some other format of your own design, use the latter.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class CodedInputStream {
|
||||
/**
|
||||
* Create a new CodedInputStream wrapping the given InputStream.
|
||||
*/
|
||||
public static CodedInputStream newInstance(final InputStream input) {
|
||||
return new CodedInputStream(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CodedInputStream wrapping the given byte array.
|
||||
*/
|
||||
public static CodedInputStream newInstance(final byte[] buf) {
|
||||
return newInstance(buf, 0, buf.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CodedInputStream wrapping the given byte array slice.
|
||||
*/
|
||||
public static CodedInputStream newInstance(final byte[] buf, final int off,
|
||||
final int len) {
|
||||
return new CodedInputStream(buf, off, len);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// begin osmand change
|
||||
public static CodedInputStream newInstance(RandomAccessFile raf) {
|
||||
return new CodedInputStream(raf);
|
||||
}
|
||||
// end osmand change
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to read a field tag, returning zero if we have reached EOF.
|
||||
* Protocol message parsers use this to read tags, since a protocol message
|
||||
* may legally end wherever a tag occurs, and zero is not a valid tag number.
|
||||
*/
|
||||
public int readTag() throws IOException {
|
||||
if (isAtEnd()) {
|
||||
lastTag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lastTag = readRawVarint32();
|
||||
if (WireFormat.getTagFieldNumber(lastTag) == 0) {
|
||||
// If we actually read zero (or any tag number corresponding to field
|
||||
// number zero), that's not a valid tag.
|
||||
throw InvalidProtocolBufferException.invalidTag();
|
||||
}
|
||||
return lastTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the last call to readTag() returned the given tag value.
|
||||
* This is used to verify that a nested group ended with the correct
|
||||
* end tag.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException {@code value} does not match the
|
||||
* last tag.
|
||||
*/
|
||||
public void checkLastTagWas(final int value)
|
||||
throws InvalidProtocolBufferException {
|
||||
if (lastTag != value) {
|
||||
throw InvalidProtocolBufferException.invalidEndTag();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and discards a single field, given its tag value.
|
||||
*
|
||||
* @return {@code false} if the tag is an endgroup tag, in which case
|
||||
* nothing is skipped. Otherwise, returns {@code true}.
|
||||
*/
|
||||
public boolean skipField(final int tag) throws IOException {
|
||||
switch (WireFormat.getTagWireType(tag)) {
|
||||
case WireFormat.WIRETYPE_VARINT:
|
||||
readInt32();
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_FIXED64:
|
||||
readRawLittleEndian64();
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
|
||||
skipRawBytes(readRawVarint32());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_START_GROUP:
|
||||
skipMessage();
|
||||
checkLastTagWas(
|
||||
WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
|
||||
WireFormat.WIRETYPE_END_GROUP));
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_END_GROUP:
|
||||
return false;
|
||||
case WireFormat.WIRETYPE_FIXED32:
|
||||
readRawLittleEndian32();
|
||||
return true;
|
||||
default:
|
||||
throw InvalidProtocolBufferException.invalidWireType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and discards an entire message. This will read either until EOF
|
||||
* or until an endgroup tag, whichever comes first.
|
||||
*/
|
||||
public void skipMessage() throws IOException {
|
||||
while (true) {
|
||||
final int tag = readTag();
|
||||
if (tag == 0 || !skipField(tag)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/** Read a {@code double} field value from the stream. */
|
||||
public double readDouble() throws IOException {
|
||||
return Double.longBitsToDouble(readRawLittleEndian64());
|
||||
}
|
||||
|
||||
/** Read a {@code float} field value from the stream. */
|
||||
public float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat(readRawLittleEndian32());
|
||||
}
|
||||
|
||||
/** Read a {@code uint64} field value from the stream. */
|
||||
public long readUInt64() throws IOException {
|
||||
return readRawVarint64();
|
||||
}
|
||||
|
||||
/** Read an {@code int64} field value from the stream. */
|
||||
public long readInt64() throws IOException {
|
||||
return readRawVarint64();
|
||||
}
|
||||
|
||||
/** Read an {@code int32} field value from the stream. */
|
||||
public int readInt32() throws IOException {
|
||||
return readRawVarint32();
|
||||
}
|
||||
|
||||
/** Read a {@code fixed64} field value from the stream. */
|
||||
public long readFixed64() throws IOException {
|
||||
return readRawLittleEndian64();
|
||||
}
|
||||
|
||||
/** Read a {@code fixed32} field value from the stream. */
|
||||
public int readFixed32() throws IOException {
|
||||
return readRawLittleEndian32();
|
||||
}
|
||||
|
||||
/** Read a {@code bool} field value from the stream. */
|
||||
public boolean readBool() throws IOException {
|
||||
return readRawVarint32() != 0;
|
||||
}
|
||||
|
||||
/** Read a {@code string} field value from the stream. */
|
||||
public String readString() throws IOException {
|
||||
final int size = readRawVarint32();
|
||||
if (size <= (bufferSize - bufferPos) && size > 0) {
|
||||
// Fast path: We already have the bytes in a contiguous buffer, so
|
||||
// just copy directly from it.
|
||||
final String result = new String(buffer, bufferPos, size, "UTF-8");
|
||||
bufferPos += size;
|
||||
return result;
|
||||
} else {
|
||||
// Slow path: Build a byte array first then copy it.
|
||||
return new String(readRawBytes(size), "UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
/** Read a {@code group} field value from the stream. */
|
||||
public void readGroup(final int fieldNumber,
|
||||
final MessageLite.Builder builder,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
if (recursionDepth >= recursionLimit) {
|
||||
throw InvalidProtocolBufferException.recursionLimitExceeded();
|
||||
}
|
||||
++recursionDepth;
|
||||
builder.mergeFrom(this, extensionRegistry);
|
||||
checkLastTagWas(
|
||||
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
|
||||
--recursionDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@code group} field value from the stream and merges it into the
|
||||
* given {@link UnknownFieldSet}.
|
||||
*
|
||||
* @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
|
||||
* you can just call {@link #readGroup}.
|
||||
*/
|
||||
@Deprecated
|
||||
public void readUnknownGroup(final int fieldNumber,
|
||||
final MessageLite.Builder builder)
|
||||
throws IOException {
|
||||
// We know that UnknownFieldSet will ignore any ExtensionRegistry so it
|
||||
// is safe to pass null here. (We can't call
|
||||
// ExtensionRegistry.getEmptyRegistry() because that would make this
|
||||
// class depend on ExtensionRegistry, which is not part of the lite
|
||||
// library.)
|
||||
readGroup(fieldNumber, builder, null);
|
||||
}
|
||||
|
||||
/** Read an embedded message field value from the stream. */
|
||||
public void readMessage(final MessageLite.Builder builder,
|
||||
final ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException {
|
||||
final int length = readRawVarint32();
|
||||
if (recursionDepth >= recursionLimit) {
|
||||
throw InvalidProtocolBufferException.recursionLimitExceeded();
|
||||
}
|
||||
final int oldLimit = pushLimit(length);
|
||||
++recursionDepth;
|
||||
builder.mergeFrom(this, extensionRegistry);
|
||||
checkLastTagWas(0);
|
||||
--recursionDepth;
|
||||
popLimit(oldLimit);
|
||||
}
|
||||
|
||||
/** Read a {@code bytes} field value from the stream. */
|
||||
public ByteString readBytes() throws IOException {
|
||||
final int size = readRawVarint32();
|
||||
if (size <= (bufferSize - bufferPos) && size > 0) {
|
||||
// Fast path: We already have the bytes in a contiguous buffer, so
|
||||
// just copy directly from it.
|
||||
final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
|
||||
bufferPos += size;
|
||||
return result;
|
||||
} else {
|
||||
// Slow path: Build a byte array first then copy it.
|
||||
return ByteString.copyFrom(readRawBytes(size));
|
||||
}
|
||||
}
|
||||
|
||||
/** Read a {@code uint32} field value from the stream. */
|
||||
public int readUInt32() throws IOException {
|
||||
return readRawVarint32();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an enum field value from the stream. Caller is responsible
|
||||
* for converting the numeric value to an actual enum.
|
||||
*/
|
||||
public int readEnum() throws IOException {
|
||||
return readRawVarint32();
|
||||
}
|
||||
|
||||
/** Read an {@code sfixed32} field value from the stream. */
|
||||
public int readSFixed32() throws IOException {
|
||||
return readRawLittleEndian32();
|
||||
}
|
||||
|
||||
/** Read an {@code sfixed64} field value from the stream. */
|
||||
public long readSFixed64() throws IOException {
|
||||
return readRawLittleEndian64();
|
||||
}
|
||||
|
||||
/** Read an {@code sint32} field value from the stream. */
|
||||
public int readSInt32() throws IOException {
|
||||
return decodeZigZag32(readRawVarint32());
|
||||
}
|
||||
|
||||
/** Read an {@code sint64} field value from the stream. */
|
||||
public long readSInt64() throws IOException {
|
||||
return decodeZigZag64(readRawVarint64());
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Read a raw Varint from the stream. If larger than 32 bits, discard the
|
||||
* upper bits.
|
||||
*/
|
||||
public int readRawVarint32() throws IOException {
|
||||
byte tmp = readRawByte();
|
||||
if (tmp >= 0) {
|
||||
return tmp;
|
||||
}
|
||||
int result = tmp & 0x7f;
|
||||
if ((tmp = readRawByte()) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = readRawByte()) >= 0) {
|
||||
result |= tmp << 14;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 14;
|
||||
if ((tmp = readRawByte()) >= 0) {
|
||||
result |= tmp << 21;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 21;
|
||||
result |= (tmp = readRawByte()) << 28;
|
||||
if (tmp < 0) {
|
||||
// Discard upper 32 bits.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (readRawByte() >= 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw InvalidProtocolBufferException.malformedVarint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a varint from the input one byte at a time, so that it does not
|
||||
* read any bytes after the end of the varint. If you simply wrapped the
|
||||
* stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
|
||||
* then you would probably end up reading past the end of the varint since
|
||||
* CodedInputStream buffers its input.
|
||||
*/
|
||||
static int readRawVarint32(final InputStream input) throws IOException {
|
||||
final int firstByte = input.read();
|
||||
if (firstByte == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
return readRawVarint32(firstByte, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #readRawVarint32(InputStream)}, but expects that the caller
|
||||
* has already read one byte. This allows the caller to determine if EOF
|
||||
* has been reached before attempting to read.
|
||||
*/
|
||||
static int readRawVarint32(final int firstByte,
|
||||
final InputStream input) throws IOException {
|
||||
if ((firstByte & 0x80) == 0) {
|
||||
return firstByte;
|
||||
}
|
||||
|
||||
int result = firstByte & 0x7f;
|
||||
int offset = 7;
|
||||
for (; offset < 32; offset += 7) {
|
||||
final int b = input.read();
|
||||
if (b == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
result |= (b & 0x7f) << offset;
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Keep reading up to 64 bits.
|
||||
for (; offset < 64; offset += 7) {
|
||||
final int b = input.read();
|
||||
if (b == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw InvalidProtocolBufferException.malformedVarint();
|
||||
}
|
||||
|
||||
/** Read a raw Varint from the stream. */
|
||||
public long readRawVarint64() throws IOException {
|
||||
int shift = 0;
|
||||
long result = 0;
|
||||
while (shift < 64) {
|
||||
final byte b = readRawByte();
|
||||
result |= (long)(b & 0x7F) << shift;
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
shift += 7;
|
||||
}
|
||||
throw InvalidProtocolBufferException.malformedVarint();
|
||||
}
|
||||
|
||||
/** Read a 32-bit little-endian integer from the stream. */
|
||||
public int readRawLittleEndian32() throws IOException {
|
||||
final byte b1 = readRawByte();
|
||||
final byte b2 = readRawByte();
|
||||
final byte b3 = readRawByte();
|
||||
final byte b4 = readRawByte();
|
||||
return (((int)b1 & 0xff) ) |
|
||||
(((int)b2 & 0xff) << 8) |
|
||||
(((int)b3 & 0xff) << 16) |
|
||||
(((int)b4 & 0xff) << 24);
|
||||
}
|
||||
|
||||
/** Read a 64-bit little-endian integer from the stream. */
|
||||
public long readRawLittleEndian64() throws IOException {
|
||||
final byte b1 = readRawByte();
|
||||
final byte b2 = readRawByte();
|
||||
final byte b3 = readRawByte();
|
||||
final byte b4 = readRawByte();
|
||||
final byte b5 = readRawByte();
|
||||
final byte b6 = readRawByte();
|
||||
final byte b7 = readRawByte();
|
||||
final byte b8 = readRawByte();
|
||||
return (((long)b1 & 0xff) ) |
|
||||
(((long)b2 & 0xff) << 8) |
|
||||
(((long)b3 & 0xff) << 16) |
|
||||
(((long)b4 & 0xff) << 24) |
|
||||
(((long)b5 & 0xff) << 32) |
|
||||
(((long)b6 & 0xff) << 40) |
|
||||
(((long)b7 & 0xff) << 48) |
|
||||
(((long)b8 & 0xff) << 56);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
|
||||
* into values that can be efficiently encoded with varint. (Otherwise,
|
||||
* negative values must be sign-extended to 64 bits to be varint encoded,
|
||||
* thus always taking 10 bytes on the wire.)
|
||||
*
|
||||
* @param n An unsigned 32-bit integer, stored in a signed int because
|
||||
* Java has no explicit unsigned support.
|
||||
* @return A signed 32-bit integer.
|
||||
*/
|
||||
public static int decodeZigZag32(final int n) {
|
||||
return (n >>> 1) ^ -(n & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
|
||||
* into values that can be efficiently encoded with varint. (Otherwise,
|
||||
* negative values must be sign-extended to 64 bits to be varint encoded,
|
||||
* thus always taking 10 bytes on the wire.)
|
||||
*
|
||||
* @param n An unsigned 64-bit integer, stored in a signed int because
|
||||
* Java has no explicit unsigned support.
|
||||
* @return A signed 64-bit integer.
|
||||
*/
|
||||
public static long decodeZigZag64(final long n) {
|
||||
return (n >>> 1) ^ -(n & 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
private final byte[] buffer;
|
||||
private RandomAccessFile raf;
|
||||
private int bufferSize;
|
||||
private int bufferSizeAfterLimit;
|
||||
private int bufferPos;
|
||||
private final InputStream input;
|
||||
private int lastTag;
|
||||
|
||||
/**
|
||||
* The total number of bytes read before the current buffer. The total
|
||||
* bytes read up to the current position can be computed as
|
||||
* {@code totalBytesRetired + bufferPos}. This value may be negative if
|
||||
* reading started in the middle of the current buffer (e.g. if the
|
||||
* constructor that takes a byte array and an offset was used).
|
||||
*/
|
||||
private int totalBytesRetired;
|
||||
|
||||
/** The absolute position of the end of the current message. */
|
||||
private int currentLimit = Integer.MAX_VALUE;
|
||||
|
||||
/** See setRecursionLimit() */
|
||||
private int recursionDepth;
|
||||
private int recursionLimit = DEFAULT_RECURSION_LIMIT;
|
||||
|
||||
/** See setSizeLimit() */
|
||||
private int sizeLimit = DEFAULT_SIZE_LIMIT;
|
||||
|
||||
private static final int DEFAULT_RECURSION_LIMIT = 64;
|
||||
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
|
||||
private static final int BUFFER_SIZE = 5 * 1024;
|
||||
|
||||
|
||||
private CodedInputStream(final byte[] buffer, final int off, final int len) {
|
||||
this.buffer = buffer;
|
||||
bufferSize = off + len;
|
||||
bufferPos = off;
|
||||
totalBytesRetired = -off;
|
||||
input = null;
|
||||
}
|
||||
|
||||
private CodedInputStream(final InputStream input) {
|
||||
buffer = new byte[BUFFER_SIZE];
|
||||
bufferSize = 0;
|
||||
bufferPos = 0;
|
||||
totalBytesRetired = 0;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
private CodedInputStream(final RandomAccessFile raf) {
|
||||
buffer = new byte[BUFFER_SIZE];
|
||||
this.bufferSize = 0;
|
||||
bufferPos = 0;
|
||||
totalBytesRetired = 0;
|
||||
this.raf = raf;
|
||||
input = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum message recursion depth. In order to prevent malicious
|
||||
* messages from causing stack overflows, {@code CodedInputStream} limits
|
||||
* how deeply messages may be nested. The default limit is 64.
|
||||
*
|
||||
* @return the old limit.
|
||||
*/
|
||||
public int setRecursionLimit(final int limit) {
|
||||
if (limit < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Recursion limit cannot be negative: " + limit);
|
||||
}
|
||||
final int oldLimit = recursionLimit;
|
||||
recursionLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum message size. In order to prevent malicious
|
||||
* messages from exhausting memory or causing integer overflows,
|
||||
* {@code CodedInputStream} limits how large a message may be.
|
||||
* The default limit is 64MB. You should set this limit as small
|
||||
* as you can without harming your app's functionality. Note that
|
||||
* size limits only apply when reading from an {@code InputStream}, not
|
||||
* when constructed around a raw byte array (nor with
|
||||
* {@link ByteString#newCodedInput}).
|
||||
* <p>
|
||||
* If you want to read several messages from a single CodedInputStream, you
|
||||
* could call {@link #resetSizeCounter()} after each one to avoid hitting the
|
||||
* size limit.
|
||||
*
|
||||
* @return the old limit.
|
||||
*/
|
||||
public int setSizeLimit(final int limit) {
|
||||
if (limit < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Size limit cannot be negative: " + limit);
|
||||
}
|
||||
final int oldLimit = sizeLimit;
|
||||
sizeLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
|
||||
*/
|
||||
public void resetSizeCounter() {
|
||||
totalBytesRetired = -bufferPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
|
||||
* is called when descending into a length-delimited embedded message.
|
||||
*
|
||||
* <p>Note that {@code pushLimit()} does NOT affect how many bytes the
|
||||
* {@code CodedInputStream} reads from an underlying {@code InputStream} when
|
||||
* refreshing its buffer. If you need to prevent reading past a certain
|
||||
* point in the underlying {@code InputStream} (e.g. because you expect it to
|
||||
* contain more data after the end of the message which you need to handle
|
||||
* differently) then you must place a wrapper around you {@code InputStream}
|
||||
* which limits the amount of data that can be read from it.
|
||||
*
|
||||
* @return the old limit.
|
||||
*/
|
||||
public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
|
||||
if (byteLimit < 0) {
|
||||
throw InvalidProtocolBufferException.negativeSize();
|
||||
}
|
||||
byteLimit += totalBytesRetired + bufferPos;
|
||||
final int oldLimit = currentLimit;
|
||||
if (byteLimit > oldLimit) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
currentLimit = byteLimit;
|
||||
|
||||
recomputeBufferSizeAfterLimit();
|
||||
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
private void recomputeBufferSizeAfterLimit() {
|
||||
bufferSize += bufferSizeAfterLimit;
|
||||
final int bufferEnd = totalBytesRetired + bufferSize;
|
||||
if (bufferEnd > currentLimit) {
|
||||
// Limit is in current buffer.
|
||||
bufferSizeAfterLimit = bufferEnd - currentLimit;
|
||||
bufferSize -= bufferSizeAfterLimit;
|
||||
} else {
|
||||
bufferSizeAfterLimit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards the current limit, returning to the previous limit.
|
||||
*
|
||||
* @param oldLimit The old limit, as returned by {@code pushLimit}.
|
||||
*/
|
||||
public void popLimit(final int oldLimit) {
|
||||
currentLimit = oldLimit;
|
||||
recomputeBufferSizeAfterLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes to be read before the current limit.
|
||||
* If no limit is set, returns -1.
|
||||
*/
|
||||
public int getBytesUntilLimit() {
|
||||
if (currentLimit == Integer.MAX_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int currentAbsolutePosition = totalBytesRetired + bufferPos;
|
||||
return currentLimit - currentAbsolutePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream has reached the end of the input. This is the
|
||||
* case if either the end of the underlying input source has been reached or
|
||||
* if the stream has reached a limit created using {@link #pushLimit(int)}.
|
||||
*/
|
||||
public boolean isAtEnd() throws IOException {
|
||||
return bufferPos == bufferSize && !refillBuffer(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The total bytes read up to the current position. Calling
|
||||
* {@link #resetSizeCounter()} resets this value to zero.
|
||||
*/
|
||||
public int getTotalBytesRead() {
|
||||
return totalBytesRetired + bufferPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called with {@code this.buffer} is empty to read more bytes from the
|
||||
* input. If {@code mustSucceed} is true, refillBuffer() gurantees that
|
||||
* either there will be at least one byte in the buffer when it returns
|
||||
* or it will throw an exception. If {@code mustSucceed} is false,
|
||||
* refillBuffer() returns false if no more bytes were available.
|
||||
*/
|
||||
private boolean refillBuffer(final boolean mustSucceed) throws IOException {
|
||||
if (bufferPos < bufferSize) {
|
||||
throw new IllegalStateException(
|
||||
"refillBuffer() called when buffer wasn't empty.");
|
||||
}
|
||||
|
||||
if (totalBytesRetired + bufferSize == currentLimit) {
|
||||
// Oops, we hit a limit.
|
||||
if (mustSucceed) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
totalBytesRetired += bufferSize;
|
||||
|
||||
bufferPos = 0;
|
||||
if (raf != null) {
|
||||
// osmand change
|
||||
long remain = raf.length() - raf.getFilePointer();
|
||||
bufferSize = (int) Math.min(remain, buffer.length);
|
||||
if(bufferSize > 0) {
|
||||
raf.readFully(buffer, 0, bufferSize);
|
||||
} else {
|
||||
bufferSize = -1;
|
||||
}
|
||||
} else {
|
||||
bufferSize = (input == null) ? -1 : input.read(buffer);
|
||||
}
|
||||
if (bufferSize == 0 || bufferSize < -1) {
|
||||
throw new IllegalStateException(
|
||||
"InputStream#read(byte[]) returned invalid result: " + bufferSize +
|
||||
"\nThe InputStream implementation is buggy.");
|
||||
}
|
||||
if (bufferSize == -1) {
|
||||
bufferSize = 0;
|
||||
if (mustSucceed) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
recomputeBufferSizeAfterLimit();
|
||||
final int totalBytesRead =
|
||||
totalBytesRetired + bufferSize + bufferSizeAfterLimit;
|
||||
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
|
||||
throw InvalidProtocolBufferException.sizeLimitExceeded();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one byte from the input.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException The end of the stream or the current
|
||||
* limit was reached.
|
||||
*/
|
||||
public byte readRawByte() throws IOException {
|
||||
if (bufferPos == bufferSize) {
|
||||
refillBuffer(true);
|
||||
}
|
||||
return buffer[bufferPos++];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a fixed size of bytes from the input.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException The end of the stream or the current
|
||||
* limit was reached.
|
||||
*/
|
||||
public byte[] readRawBytes(final int size) throws IOException {
|
||||
if (size < 0) {
|
||||
throw InvalidProtocolBufferException.negativeSize();
|
||||
}
|
||||
|
||||
if (totalBytesRetired + bufferPos + size > currentLimit) {
|
||||
// Read to the end of the stream anyway.
|
||||
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
|
||||
if (size <= bufferSize - bufferPos) {
|
||||
// We have all the bytes we need already.
|
||||
final byte[] bytes = new byte[size];
|
||||
System.arraycopy(buffer, bufferPos, bytes, 0, size);
|
||||
bufferPos += size;
|
||||
return bytes;
|
||||
} else if (size < BUFFER_SIZE) {
|
||||
// Reading more bytes than are in the buffer, but not an excessive number
|
||||
// of bytes. We can safely allocate the resulting array ahead of time.
|
||||
|
||||
// First copy what we have.
|
||||
final byte[] bytes = new byte[size];
|
||||
int pos = bufferSize - bufferPos;
|
||||
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
|
||||
bufferPos = bufferSize;
|
||||
|
||||
// We want to use refillBuffer() and then copy from the buffer into our
|
||||
// byte array rather than reading directly into our byte array because
|
||||
// the input may be unbuffered.
|
||||
refillBuffer(true);
|
||||
|
||||
while (size - pos > bufferSize) {
|
||||
System.arraycopy(buffer, 0, bytes, pos, bufferSize);
|
||||
pos += bufferSize;
|
||||
bufferPos = bufferSize;
|
||||
refillBuffer(true);
|
||||
}
|
||||
|
||||
System.arraycopy(buffer, 0, bytes, pos, size - pos);
|
||||
bufferPos = size - pos;
|
||||
|
||||
return bytes;
|
||||
} else {
|
||||
// The size is very large. For security reasons, we can't allocate the
|
||||
// entire byte array yet. The size comes directly from the input, so a
|
||||
// maliciously-crafted message could provide a bogus very large size in
|
||||
// order to trick the app into allocating a lot of memory. We avoid this
|
||||
// by allocating and reading only a small chunk at a time, so that the
|
||||
// malicious message must actually *be* extremely large to cause
|
||||
// problems. Meanwhile, we limit the allowed size of a message elsewhere.
|
||||
|
||||
// Remember the buffer markers since we'll have to copy the bytes out of
|
||||
// it later.
|
||||
final int originalBufferPos = bufferPos;
|
||||
final int originalBufferSize = bufferSize;
|
||||
|
||||
// Mark the current buffer consumed.
|
||||
totalBytesRetired += bufferSize;
|
||||
bufferPos = 0;
|
||||
bufferSize = 0;
|
||||
|
||||
// Read all the rest of the bytes we need.
|
||||
int sizeLeft = size - (originalBufferSize - originalBufferPos);
|
||||
final List<byte[]> chunks = new ArrayList<byte[]>();
|
||||
|
||||
while (sizeLeft > 0) {
|
||||
final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
|
||||
int pos = 0;
|
||||
while (pos < chunk.length) {
|
||||
|
||||
final int n;
|
||||
// osmand change
|
||||
if(raf != null) {
|
||||
raf.readFully(chunk, pos, chunk.length - pos);
|
||||
n = chunk.length - pos;
|
||||
} else {
|
||||
n = (input == null) ? -1 :
|
||||
input.read(chunk, pos, chunk.length - pos);
|
||||
}
|
||||
if (n == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
totalBytesRetired += n;
|
||||
pos += n;
|
||||
}
|
||||
sizeLeft -= chunk.length;
|
||||
chunks.add(chunk);
|
||||
}
|
||||
|
||||
// OK, got everything. Now concatenate it all into one buffer.
|
||||
final byte[] bytes = new byte[size];
|
||||
|
||||
// Start by copying the leftover bytes from this.buffer.
|
||||
int pos = originalBufferSize - originalBufferPos;
|
||||
System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
|
||||
|
||||
// And now all the chunks.
|
||||
for (final byte[] chunk : chunks) {
|
||||
System.arraycopy(chunk, 0, bytes, pos, chunk.length);
|
||||
pos += chunk.length;
|
||||
}
|
||||
// Done.
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and discards {@code size} bytes.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException The end of the stream or the current
|
||||
* limit was reached.
|
||||
*/
|
||||
public void skipRawBytes(final int size) throws IOException {
|
||||
if (size < 0) {
|
||||
throw InvalidProtocolBufferException.negativeSize();
|
||||
}
|
||||
|
||||
if (totalBytesRetired + bufferPos + size > currentLimit) {
|
||||
// Read to the end of the stream anyway.
|
||||
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
|
||||
if (size <= bufferSize - bufferPos) {
|
||||
// We have all the bytes we need already.
|
||||
bufferPos += size;
|
||||
} else {
|
||||
// Skipping more bytes than are in the buffer. First skip what we have.
|
||||
int pos = bufferSize - bufferPos;
|
||||
totalBytesRetired += bufferSize; // ? pos incorrect
|
||||
bufferPos = 0;
|
||||
bufferSize = 0;
|
||||
|
||||
// Then skip directly from the InputStream for the rest.
|
||||
while (pos < size) {
|
||||
// osmand change
|
||||
final int n ;
|
||||
if(raf != null) {
|
||||
n = raf.skipBytes(size - pos);
|
||||
} else {
|
||||
n = (input == null) ? -1 : (int) input.skip(size - pos);
|
||||
}
|
||||
if (n <= 0) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
pos += n;
|
||||
totalBytesRetired += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// osmand change
|
||||
public void seek(long pointer) throws IOException {
|
||||
if (pointer - totalBytesRetired >= 0 && pointer - totalBytesRetired < bufferSize) {
|
||||
if (pointer > currentLimit) {
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
bufferPos = (int) (pointer - totalBytesRetired);
|
||||
} else {
|
||||
totalBytesRetired = (int) pointer;
|
||||
bufferSizeAfterLimit = 0;
|
||||
raf.seek(pointer);
|
||||
bufferPos = 0;
|
||||
bufferSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
825
OsmAnd-java/src/com/google/protobuf/CodedInputStreamRAF.java
Normal file
825
OsmAnd-java/src/com/google/protobuf/CodedInputStreamRAF.java
Normal file
|
@ -0,0 +1,825 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reads and decodes protocol message fields.
|
||||
*
|
||||
* This class contains two kinds of methods: methods that read specific
|
||||
* protocol message constructs and field types (e.g. {@link #readTag()} and
|
||||
* {@link #readInt32()}) and methods that read low-level values (e.g.
|
||||
* {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
|
||||
* encoded protocol messages, you should use the former methods, but if you are
|
||||
* reading some other format of your own design, use the latter.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
* OSMAND change
|
||||
*/
|
||||
public final class CodedInputStreamRAF {
|
||||
/**
|
||||
* Create a new CodedInputStream wrapping the given InputStream.
|
||||
*/
|
||||
public static CodedInputStreamRAF newInstance(RandomAccessFile raf) {
|
||||
return new CodedInputStreamRAF(raf, BUFFER_SIZE_DEF);
|
||||
}
|
||||
|
||||
public static CodedInputStreamRAF newInstance(RandomAccessFile raf, int bufferSize) {
|
||||
return new CodedInputStreamRAF(raf, bufferSize);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Attempt to read a field tag, returning zero if we have reached EOF.
|
||||
* Protocol message parsers use this to read tags, since a protocol message
|
||||
* may legally end wherever a tag occurs, and zero is not a valid tag number.
|
||||
*/
|
||||
public int readTag() throws IOException {
|
||||
if (isAtEnd()) {
|
||||
lastTag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lastTag = readRawVarint32();
|
||||
if (WireFormat.getTagFieldNumber(lastTag) == 0) {
|
||||
// If we actually read zero (or any tag number corresponding to field
|
||||
// number zero), that's not a valid tag.
|
||||
throw InvalidProtocolBufferException.invalidTag();
|
||||
}
|
||||
return lastTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the last call to readTag() returned the given tag value.
|
||||
* This is used to verify that a nested group ended with the correct
|
||||
* end tag.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException {@code value} does not match the
|
||||
* last tag.
|
||||
*/
|
||||
public void checkLastTagWas(final int value)
|
||||
throws InvalidProtocolBufferException {
|
||||
if (lastTag != value) {
|
||||
throw InvalidProtocolBufferException.invalidEndTag();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and discards a single field, given its tag value.
|
||||
*
|
||||
* @return {@code false} if the tag is an endgroup tag, in which case
|
||||
* nothing is skipped. Otherwise, returns {@code true}.
|
||||
*/
|
||||
public boolean skipField(final int tag) throws IOException {
|
||||
switch (WireFormat.getTagWireType(tag)) {
|
||||
case WireFormat.WIRETYPE_VARINT:
|
||||
readInt32();
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_FIXED64:
|
||||
readRawLittleEndian64();
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
|
||||
skipRawBytes(readRawVarint32());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_START_GROUP:
|
||||
skipMessage();
|
||||
checkLastTagWas(
|
||||
WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
|
||||
WireFormat.WIRETYPE_END_GROUP));
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_END_GROUP:
|
||||
return false;
|
||||
case WireFormat.WIRETYPE_FIXED32:
|
||||
readRawLittleEndian32();
|
||||
return true;
|
||||
default:
|
||||
throw InvalidProtocolBufferException.invalidWireType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and discards an entire message. This will read either until EOF
|
||||
* or until an endgroup tag, whichever comes first.
|
||||
*/
|
||||
public void skipMessage() throws IOException {
|
||||
while (true) {
|
||||
final int tag = readTag();
|
||||
if (tag == 0 || !skipField(tag)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/** Read a {@code double} field value from the stream. */
|
||||
public double readDouble() throws IOException {
|
||||
return Double.longBitsToDouble(readRawLittleEndian64());
|
||||
}
|
||||
|
||||
/** Read a {@code float} field value from the stream. */
|
||||
public float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat(readRawLittleEndian32());
|
||||
}
|
||||
|
||||
/** Read a {@code uint64} field value from the stream. */
|
||||
public long readUInt64() throws IOException {
|
||||
return readRawVarint64();
|
||||
}
|
||||
|
||||
/** Read an {@code int64} field value from the stream. */
|
||||
public long readInt64() throws IOException {
|
||||
return readRawVarint64();
|
||||
}
|
||||
|
||||
/** Read an {@code int32} field value from the stream. */
|
||||
public int readInt32() throws IOException {
|
||||
return readRawVarint32();
|
||||
}
|
||||
|
||||
/** Read a {@code fixed64} field value from the stream. */
|
||||
public long readFixed64() throws IOException {
|
||||
return readRawLittleEndian64();
|
||||
}
|
||||
|
||||
/** Read a {@code fixed32} field value from the stream. */
|
||||
public int readFixed32() throws IOException {
|
||||
return readRawLittleEndian32();
|
||||
}
|
||||
|
||||
/** Read a {@code bool} field value from the stream. */
|
||||
public boolean readBool() throws IOException {
|
||||
return readRawVarint32() != 0;
|
||||
}
|
||||
|
||||
/** Read a {@code string} field value from the stream. */
|
||||
public String readString() throws IOException {
|
||||
final int size = readRawVarint32();
|
||||
if (size <= (bufferSize - bufferPos) && size > 0) {
|
||||
// Fast path: We already have the bytes in a contiguous buffer, so
|
||||
// just copy directly from it.
|
||||
final String result = new String(buffer, bufferPos, size, "UTF-8");
|
||||
bufferPos += size;
|
||||
return result;
|
||||
} else {
|
||||
// Slow path: Build a byte array first then copy it.
|
||||
return new String(readRawBytes(size), "UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Read a {@code bytes} field value from the stream. */
|
||||
public ByteString readBytes() throws IOException {
|
||||
final int size = readRawVarint32();
|
||||
if (size <= (bufferSize - bufferPos) && size > 0) {
|
||||
// Fast path: We already have the bytes in a contiguous buffer, so
|
||||
// just copy directly from it.
|
||||
final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
|
||||
bufferPos += size;
|
||||
return result;
|
||||
} else {
|
||||
// Slow path: Build a byte array first then copy it.
|
||||
return ByteString.copyFrom(readRawBytes(size));
|
||||
}
|
||||
}
|
||||
|
||||
/** Read a {@code uint32} field value from the stream. */
|
||||
public int readUInt32() throws IOException {
|
||||
return readRawVarint32();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an enum field value from the stream. Caller is responsible
|
||||
* for converting the numeric value to an actual enum.
|
||||
*/
|
||||
public int readEnum() throws IOException {
|
||||
return readRawVarint32();
|
||||
}
|
||||
|
||||
/** Read an {@code sfixed32} field value from the stream. */
|
||||
public int readSFixed32() throws IOException {
|
||||
return readRawLittleEndian32();
|
||||
}
|
||||
|
||||
/** Read an {@code sfixed64} field value from the stream. */
|
||||
public long readSFixed64() throws IOException {
|
||||
return readRawLittleEndian64();
|
||||
}
|
||||
|
||||
/** Read an {@code sint32} field value from the stream. */
|
||||
public int readSInt32() throws IOException {
|
||||
return decodeZigZag32(readRawVarint32());
|
||||
}
|
||||
|
||||
/** Read an {@code sint64} field value from the stream. */
|
||||
public long readSInt64() throws IOException {
|
||||
return decodeZigZag64(readRawVarint64());
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Read a raw Varint from the stream. If larger than 32 bits, discard the
|
||||
* upper bits.
|
||||
*/
|
||||
public int readRawVarint32() throws IOException {
|
||||
byte tmp = readRawByte();
|
||||
if (tmp >= 0) {
|
||||
return tmp;
|
||||
}
|
||||
int result = tmp & 0x7f;
|
||||
if ((tmp = readRawByte()) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = readRawByte()) >= 0) {
|
||||
result |= tmp << 14;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 14;
|
||||
if ((tmp = readRawByte()) >= 0) {
|
||||
result |= tmp << 21;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 21;
|
||||
result |= (tmp = readRawByte()) << 28;
|
||||
if (tmp < 0) {
|
||||
// Discard upper 32 bits.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (readRawByte() >= 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw InvalidProtocolBufferException.malformedVarint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a varint from the input one byte at a time, so that it does not
|
||||
* read any bytes after the end of the varint. If you simply wrapped the
|
||||
* stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
|
||||
* then you would probably end up reading past the end of the varint since
|
||||
* CodedInputStream buffers its input.
|
||||
*/
|
||||
static int readRawVarint32(final InputStream input) throws IOException {
|
||||
final int firstByte = input.read();
|
||||
if (firstByte == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
return readRawVarint32(firstByte, input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #readRawVarint32(InputStream)}, but expects that the caller
|
||||
* has already read one byte. This allows the caller to determine if EOF
|
||||
* has been reached before attempting to read.
|
||||
*/
|
||||
static int readRawVarint32(final int firstByte,
|
||||
final InputStream input) throws IOException {
|
||||
if ((firstByte & 0x80) == 0) {
|
||||
return firstByte;
|
||||
}
|
||||
|
||||
int result = firstByte & 0x7f;
|
||||
int offset = 7;
|
||||
for (; offset < 32; offset += 7) {
|
||||
final int b = input.read();
|
||||
if (b == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
result |= (b & 0x7f) << offset;
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Keep reading up to 64 bits.
|
||||
for (; offset < 64; offset += 7) {
|
||||
final int b = input.read();
|
||||
if (b == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw InvalidProtocolBufferException.malformedVarint();
|
||||
}
|
||||
|
||||
/** Read a raw Varint from the stream. */
|
||||
public long readRawVarint64() throws IOException {
|
||||
int shift = 0;
|
||||
long result = 0;
|
||||
while (shift < 64) {
|
||||
final byte b = readRawByte();
|
||||
result |= (long)(b & 0x7F) << shift;
|
||||
if ((b & 0x80) == 0) {
|
||||
return result;
|
||||
}
|
||||
shift += 7;
|
||||
}
|
||||
throw InvalidProtocolBufferException.malformedVarint();
|
||||
}
|
||||
|
||||
/** Read a 32-bit little-endian integer from the stream. */
|
||||
public int readRawLittleEndian32() throws IOException {
|
||||
final byte b1 = readRawByte();
|
||||
final byte b2 = readRawByte();
|
||||
final byte b3 = readRawByte();
|
||||
final byte b4 = readRawByte();
|
||||
return (((int)b1 & 0xff) ) |
|
||||
(((int)b2 & 0xff) << 8) |
|
||||
(((int)b3 & 0xff) << 16) |
|
||||
(((int)b4 & 0xff) << 24);
|
||||
}
|
||||
|
||||
/** Read a 64-bit little-endian integer from the stream. */
|
||||
public long readRawLittleEndian64() throws IOException {
|
||||
final byte b1 = readRawByte();
|
||||
final byte b2 = readRawByte();
|
||||
final byte b3 = readRawByte();
|
||||
final byte b4 = readRawByte();
|
||||
final byte b5 = readRawByte();
|
||||
final byte b6 = readRawByte();
|
||||
final byte b7 = readRawByte();
|
||||
final byte b8 = readRawByte();
|
||||
return (((long)b1 & 0xff) ) |
|
||||
(((long)b2 & 0xff) << 8) |
|
||||
(((long)b3 & 0xff) << 16) |
|
||||
(((long)b4 & 0xff) << 24) |
|
||||
(((long)b5 & 0xff) << 32) |
|
||||
(((long)b6 & 0xff) << 40) |
|
||||
(((long)b7 & 0xff) << 48) |
|
||||
(((long)b8 & 0xff) << 56);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
|
||||
* into values that can be efficiently encoded with varint. (Otherwise,
|
||||
* negative values must be sign-extended to 64 bits to be varint encoded,
|
||||
* thus always taking 10 bytes on the wire.)
|
||||
*
|
||||
* @param n An unsigned 32-bit integer, stored in a signed int because
|
||||
* Java has no explicit unsigned support.
|
||||
* @return A signed 32-bit integer.
|
||||
*/
|
||||
public static int decodeZigZag32(final int n) {
|
||||
return (n >>> 1) ^ -(n & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
|
||||
* into values that can be efficiently encoded with varint. (Otherwise,
|
||||
* negative values must be sign-extended to 64 bits to be varint encoded,
|
||||
* thus always taking 10 bytes on the wire.)
|
||||
*
|
||||
* @param n An unsigned 64-bit integer, stored in a signed int because
|
||||
* Java has no explicit unsigned support.
|
||||
* @return A signed 64-bit integer.
|
||||
*/
|
||||
public static long decodeZigZag64(final long n) {
|
||||
return (n >>> 1) ^ -(n & 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
private final byte[] buffer;
|
||||
private int bufferSize;
|
||||
private int bufferSizeAfterLimit;
|
||||
private int bufferPos;
|
||||
private final RandomAccessFile raf;
|
||||
private int lastTag;
|
||||
|
||||
/**
|
||||
* The total number of bytes read before the current buffer. The total
|
||||
* bytes read up to the current position can be computed as
|
||||
* {@code totalBytesRetired + bufferPos}. This value may be negative if
|
||||
* reading started in the middle of the current buffer (e.g. if the
|
||||
* constructor that takes a byte array and an offset was used).
|
||||
*/
|
||||
private int totalBytesRetired;
|
||||
|
||||
/** The absolute position of the end of the current message. */
|
||||
private int currentLimit = Integer.MAX_VALUE;
|
||||
|
||||
/** See setRecursionLimit() */
|
||||
private int recursionDepth;
|
||||
private int recursionLimit = DEFAULT_RECURSION_LIMIT;
|
||||
|
||||
/** See setSizeLimit() */
|
||||
private int sizeLimit = DEFAULT_SIZE_LIMIT;
|
||||
|
||||
private static final int DEFAULT_RECURSION_LIMIT = 64;
|
||||
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
|
||||
private static final int BUFFER_SIZE_DEF = 4096;
|
||||
private int BUFFER_SIZE = BUFFER_SIZE_DEF;
|
||||
|
||||
|
||||
private CodedInputStreamRAF(final RandomAccessFile raf, int bufferSize) {
|
||||
BUFFER_SIZE = bufferSize;
|
||||
buffer = new byte[BUFFER_SIZE];
|
||||
this.bufferSize = 0;
|
||||
bufferPos = 0;
|
||||
totalBytesRetired = 0;
|
||||
this.raf = raf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum message recursion depth. In order to prevent malicious
|
||||
* messages from causing stack overflows, {@code CodedInputStream} limits
|
||||
* how deeply messages may be nested. The default limit is 64.
|
||||
*
|
||||
* @return the old limit.
|
||||
*/
|
||||
public int setRecursionLimit(final int limit) {
|
||||
if (limit < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Recursion limit cannot be negative: " + limit);
|
||||
}
|
||||
final int oldLimit = recursionLimit;
|
||||
recursionLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum message size. In order to prevent malicious
|
||||
* messages from exhausting memory or causing integer overflows,
|
||||
* {@code CodedInputStream} limits how large a message may be.
|
||||
* The default limit is 64MB. You should set this limit as small
|
||||
* as you can without harming your app's functionality. Note that
|
||||
* size limits only apply when reading from an {@code InputStream}, not
|
||||
* when constructed around a raw byte array (nor with
|
||||
* {@link ByteString#newCodedInput}).
|
||||
* <p>
|
||||
* If you want to read several messages from a single CodedInputStream, you
|
||||
* could call {@link #resetSizeCounter()} after each one to avoid hitting the
|
||||
* size limit.
|
||||
*
|
||||
* @return the old limit.
|
||||
*/
|
||||
public int setSizeLimit(final int limit) {
|
||||
if (limit < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Size limit cannot be negative: " + limit);
|
||||
}
|
||||
final int oldLimit = sizeLimit;
|
||||
sizeLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
|
||||
*/
|
||||
public void resetSizeCounter() {
|
||||
totalBytesRetired = -bufferPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
|
||||
* is called when descending into a length-delimited embedded message.
|
||||
*
|
||||
* <p>Note that {@code pushLimit()} does NOT affect how many bytes the
|
||||
* {@code CodedInputStream} reads from an underlying {@code InputStream} when
|
||||
* refreshing its buffer. If you need to prevent reading past a certain
|
||||
* point in the underlying {@code InputStream} (e.g. because you expect it to
|
||||
* contain more data after the end of the message which you need to handle
|
||||
* differently) then you must place a wrapper around you {@code InputStream}
|
||||
* which limits the amount of data that can be read from it.
|
||||
*
|
||||
* @return the old limit.
|
||||
*/
|
||||
public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
|
||||
if (byteLimit < 0) {
|
||||
throw InvalidProtocolBufferException.negativeSize();
|
||||
}
|
||||
byteLimit += totalBytesRetired + bufferPos;
|
||||
final int oldLimit = currentLimit;
|
||||
if (byteLimit > oldLimit) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
currentLimit = byteLimit;
|
||||
|
||||
recomputeBufferSizeAfterLimit();
|
||||
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
private void recomputeBufferSizeAfterLimit() {
|
||||
bufferSize += bufferSizeAfterLimit;
|
||||
final int bufferEnd = totalBytesRetired + bufferSize;
|
||||
if (bufferEnd > currentLimit) {
|
||||
// Limit is in current buffer.
|
||||
bufferSizeAfterLimit = bufferEnd - currentLimit;
|
||||
bufferSize -= bufferSizeAfterLimit;
|
||||
} else {
|
||||
bufferSizeAfterLimit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards the current limit, returning to the previous limit.
|
||||
*
|
||||
* @param oldLimit The old limit, as returned by {@code pushLimit}.
|
||||
*/
|
||||
public void popLimit(final int oldLimit) {
|
||||
currentLimit = oldLimit;
|
||||
recomputeBufferSizeAfterLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes to be read before the current limit.
|
||||
* If no limit is set, returns -1.
|
||||
*/
|
||||
public int getBytesUntilLimit() {
|
||||
if (currentLimit == Integer.MAX_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int currentAbsolutePosition = totalBytesRetired + bufferPos;
|
||||
return currentLimit - currentAbsolutePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream has reached the end of the input. This is the
|
||||
* case if either the end of the underlying input source has been reached or
|
||||
* if the stream has reached a limit created using {@link #pushLimit(int)}.
|
||||
*/
|
||||
public boolean isAtEnd() throws IOException {
|
||||
return bufferPos == bufferSize && !refillBuffer(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The total bytes read up to the current position. Calling
|
||||
* {@link #resetSizeCounter()} resets this value to zero.
|
||||
*/
|
||||
public int getTotalBytesRead() {
|
||||
return totalBytesRetired + bufferPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called with {@code this.buffer} is empty to read more bytes from the
|
||||
* input. If {@code mustSucceed} is true, refillBuffer() gurantees that
|
||||
* either there will be at least one byte in the buffer when it returns
|
||||
* or it will throw an exception. If {@code mustSucceed} is false,
|
||||
* refillBuffer() returns false if no more bytes were available.
|
||||
*/
|
||||
private boolean refillBuffer(final boolean mustSucceed) throws IOException {
|
||||
if (bufferPos < bufferSize) {
|
||||
throw new IllegalStateException(
|
||||
"refillBuffer() called when buffer wasn't empty.");
|
||||
}
|
||||
|
||||
if (totalBytesRetired + bufferSize == currentLimit) {
|
||||
// Oops, we hit a limit.
|
||||
if (mustSucceed) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
totalBytesRetired += bufferSize;
|
||||
|
||||
bufferPos = 0;
|
||||
// osmand change
|
||||
bufferSize = raf.read(buffer);
|
||||
if (bufferSize == 0 || bufferSize < -1) {
|
||||
throw new IllegalStateException(
|
||||
"InputStream#read(byte[]) returned invalid result: " + bufferSize +
|
||||
"\nThe InputStream implementation is buggy.");
|
||||
}
|
||||
if (bufferSize == -1) {
|
||||
bufferSize = 0;
|
||||
if (mustSucceed) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
recomputeBufferSizeAfterLimit();
|
||||
final int totalBytesRead =
|
||||
totalBytesRetired + bufferSize + bufferSizeAfterLimit;
|
||||
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
|
||||
throw InvalidProtocolBufferException.sizeLimitExceeded();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one byte from the input.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException The end of the stream or the current
|
||||
* limit was reached.
|
||||
*/
|
||||
public byte readRawByte() throws IOException {
|
||||
if (bufferPos == bufferSize) {
|
||||
refillBuffer(true);
|
||||
}
|
||||
return buffer[bufferPos++];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a fixed size of bytes from the input.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException The end of the stream or the current
|
||||
* limit was reached.
|
||||
*/
|
||||
public byte[] readRawBytes(final int size) throws IOException {
|
||||
if (size < 0) {
|
||||
throw InvalidProtocolBufferException.negativeSize();
|
||||
}
|
||||
|
||||
if (totalBytesRetired + bufferPos + size > currentLimit) {
|
||||
// Read to the end of the stream anyway.
|
||||
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
|
||||
if (size <= bufferSize - bufferPos) {
|
||||
// We have all the bytes we need already.
|
||||
final byte[] bytes = new byte[size];
|
||||
System.arraycopy(buffer, bufferPos, bytes, 0, size);
|
||||
bufferPos += size;
|
||||
return bytes;
|
||||
} else if (size < BUFFER_SIZE) {
|
||||
// Reading more bytes than are in the buffer, but not an excessive number
|
||||
// of bytes. We can safely allocate the resulting array ahead of time.
|
||||
|
||||
// First copy what we have.
|
||||
final byte[] bytes = new byte[size];
|
||||
int pos = bufferSize - bufferPos;
|
||||
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
|
||||
bufferPos = bufferSize;
|
||||
|
||||
// We want to use refillBuffer() and then copy from the buffer into our
|
||||
// byte array rather than reading directly into our byte array because
|
||||
// the input may be unbuffered.
|
||||
refillBuffer(true);
|
||||
|
||||
while (size - pos > bufferSize) {
|
||||
System.arraycopy(buffer, 0, bytes, pos, bufferSize);
|
||||
pos += bufferSize;
|
||||
bufferPos = bufferSize;
|
||||
refillBuffer(true);
|
||||
}
|
||||
|
||||
System.arraycopy(buffer, 0, bytes, pos, size - pos);
|
||||
bufferPos = size - pos;
|
||||
|
||||
return bytes;
|
||||
} else {
|
||||
// The size is very large. For security reasons, we can't allocate the
|
||||
// entire byte array yet. The size comes directly from the input, so a
|
||||
// maliciously-crafted message could provide a bogus very large size in
|
||||
// order to trick the app into allocating a lot of memory. We avoid this
|
||||
// by allocating and reading only a small chunk at a time, so that the
|
||||
// malicious message must actually *be* extremely large to cause
|
||||
// problems. Meanwhile, we limit the allowed size of a message elsewhere.
|
||||
|
||||
// Remember the buffer markers since we'll have to copy the bytes out of
|
||||
// it later.
|
||||
final int originalBufferPos = bufferPos;
|
||||
final int originalBufferSize = bufferSize;
|
||||
|
||||
// Mark the current buffer consumed.
|
||||
totalBytesRetired += bufferSize;
|
||||
bufferPos = 0;
|
||||
bufferSize = 0;
|
||||
|
||||
// Read all the rest of the bytes we need.
|
||||
int sizeLeft = size - (originalBufferSize - originalBufferPos);
|
||||
final List<byte[]> chunks = new ArrayList<byte[]>();
|
||||
|
||||
while (sizeLeft > 0) {
|
||||
final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
|
||||
int pos = 0;
|
||||
while (pos < chunk.length) {
|
||||
// osmand change
|
||||
final int n = raf.read(chunk, pos, chunk.length - pos);
|
||||
if (n == -1) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
totalBytesRetired += n;
|
||||
pos += n;
|
||||
}
|
||||
sizeLeft -= chunk.length;
|
||||
chunks.add(chunk);
|
||||
}
|
||||
|
||||
// OK, got everything. Now concatenate it all into one buffer.
|
||||
final byte[] bytes = new byte[size];
|
||||
|
||||
// Start by copying the leftover bytes from this.buffer.
|
||||
int pos = originalBufferSize - originalBufferPos;
|
||||
System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
|
||||
|
||||
// And now all the chunks.
|
||||
for (final byte[] chunk : chunks) {
|
||||
System.arraycopy(chunk, 0, bytes, pos, chunk.length);
|
||||
pos += chunk.length;
|
||||
}
|
||||
|
||||
// Done.
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and discards {@code size} bytes.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException The end of the stream or the current
|
||||
* limit was reached.
|
||||
*/
|
||||
public void skipRawBytes(final int size) throws IOException {
|
||||
if (size < 0) {
|
||||
throw InvalidProtocolBufferException.negativeSize();
|
||||
}
|
||||
|
||||
if (totalBytesRetired + bufferPos + size > currentLimit) {
|
||||
// Read to the end of the stream anyway.
|
||||
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
|
||||
if (size <= bufferSize - bufferPos) {
|
||||
// We have all the bytes we need already.
|
||||
bufferPos += size;
|
||||
} else {
|
||||
// Skipping more bytes than are in the buffer. First skip what we have.
|
||||
int pos = bufferSize - bufferPos;
|
||||
totalBytesRetired += bufferSize;
|
||||
bufferPos = 0;
|
||||
bufferSize = 0;
|
||||
|
||||
// Then skip directly from the InputStream for the rest.
|
||||
while (pos < size) {
|
||||
// osmand change
|
||||
final int n = raf.skipBytes(size - pos);
|
||||
if (n <= 0) {
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
pos += n;
|
||||
totalBytesRetired += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// osmand change
|
||||
public void seek(long pointer) throws IOException{
|
||||
if(pointer - totalBytesRetired >= 0 && pointer - totalBytesRetired < bufferSize){
|
||||
if (pointer > currentLimit) {
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.truncatedMessage();
|
||||
}
|
||||
bufferPos = (int) (pointer - totalBytesRetired);
|
||||
} else {
|
||||
totalBytesRetired = (int) pointer;
|
||||
bufferSizeAfterLimit = 0;
|
||||
raf.seek(pointer);
|
||||
bufferPos = 0;
|
||||
bufferSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
1040
OsmAnd-java/src/com/google/protobuf/CodedOutputStream.java
Normal file
1040
OsmAnd-java/src/com/google/protobuf/CodedOutputStream.java
Normal file
File diff suppressed because it is too large
Load diff
9411
OsmAnd-java/src/com/google/protobuf/DescriptorProtos.java
Normal file
9411
OsmAnd-java/src/com/google/protobuf/DescriptorProtos.java
Normal file
File diff suppressed because it is too large
Load diff
1930
OsmAnd-java/src/com/google/protobuf/Descriptors.java
Normal file
1930
OsmAnd-java/src/com/google/protobuf/Descriptors.java
Normal file
File diff suppressed because it is too large
Load diff
472
OsmAnd-java/src/com/google/protobuf/DynamicMessage.java
Normal file
472
OsmAnd-java/src/com/google/protobuf/DynamicMessage.java
Normal file
|
@ -0,0 +1,472 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Message} that can represent arbitrary types,
|
||||
* given a {@link Descriptors.Descriptor}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class DynamicMessage extends AbstractMessage {
|
||||
private final Descriptor type;
|
||||
private final FieldSet<FieldDescriptor> fields;
|
||||
private final UnknownFieldSet unknownFields;
|
||||
private int memoizedSize = -1;
|
||||
|
||||
/**
|
||||
* Construct a {@code DynamicMessage} using the given {@code FieldSet}.
|
||||
*/
|
||||
private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
|
||||
UnknownFieldSet unknownFields) {
|
||||
this.type = type;
|
||||
this.fields = fields;
|
||||
this.unknownFields = unknownFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code DynamicMessage} representing the default instance of the
|
||||
* given type.
|
||||
*/
|
||||
public static DynamicMessage getDefaultInstance(Descriptor type) {
|
||||
return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
|
||||
UnknownFieldSet.getDefaultInstance());
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from the given input stream. */
|
||||
public static DynamicMessage parseFrom(Descriptor type,
|
||||
CodedInputStream input)
|
||||
throws IOException {
|
||||
return newBuilder(type).mergeFrom(input).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from the given input stream. */
|
||||
public static DynamicMessage parseFrom(
|
||||
Descriptor type,
|
||||
CodedInputStream input,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws IOException {
|
||||
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, ByteString data,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as a message of the given type and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, byte[] data,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from {@code input} and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, InputStream input)
|
||||
throws IOException {
|
||||
return newBuilder(type).mergeFrom(input).buildParsed();
|
||||
}
|
||||
|
||||
/** Parse a message of the given type from {@code input} and return it. */
|
||||
public static DynamicMessage parseFrom(Descriptor type, InputStream input,
|
||||
ExtensionRegistry extensionRegistry)
|
||||
throws IOException {
|
||||
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
|
||||
}
|
||||
|
||||
/** Construct a {@link Message.Builder} for the given type. */
|
||||
public static Builder newBuilder(Descriptor type) {
|
||||
return new Builder(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link Message.Builder} for a message of the same type as
|
||||
* {@code prototype}, and initialize it with {@code prototype}'s contents.
|
||||
*/
|
||||
public static Builder newBuilder(Message prototype) {
|
||||
return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Implementation of Message interface.
|
||||
|
||||
@Override
|
||||
public Descriptor getDescriptorForType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage getDefaultInstanceForType() {
|
||||
return getDefaultInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<FieldDescriptor, Object> getAllFields() {
|
||||
return fields.getAllFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.hasField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
Object result = fields.getField(field);
|
||||
if (result == null) {
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
result = getDefaultInstance(field.getMessageType());
|
||||
} else {
|
||||
result = field.getDefaultValue();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedFieldCount(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(FieldDescriptor field, int index) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedField(field, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
private static boolean isInitialized(Descriptor type,
|
||||
FieldSet<FieldDescriptor> fields) {
|
||||
// Check that all required fields are present.
|
||||
for (final FieldDescriptor field : type.getFields()) {
|
||||
if (field.isRequired()) {
|
||||
if (!fields.hasField(field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that embedded messages are initialized.
|
||||
return fields.isInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return isInitialized(type, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(CodedOutputStream output) throws IOException {
|
||||
if (type.getOptions().getMessageSetWireFormat()) {
|
||||
fields.writeMessageSetTo(output);
|
||||
unknownFields.writeAsMessageSetTo(output);
|
||||
} else {
|
||||
fields.writeTo(output);
|
||||
unknownFields.writeTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSize;
|
||||
if (size != -1) return size;
|
||||
|
||||
if (type.getOptions().getMessageSetWireFormat()) {
|
||||
size = fields.getMessageSetSerializedSize();
|
||||
size += unknownFields.getSerializedSizeAsMessageSet();
|
||||
} else {
|
||||
size = fields.getSerializedSize();
|
||||
size += unknownFields.getSerializedSize();
|
||||
}
|
||||
|
||||
memoizedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForType() {
|
||||
return new Builder(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return newBuilderForType().mergeFrom(this);
|
||||
}
|
||||
|
||||
/** Verifies that the field is a field of this message. */
|
||||
private void verifyContainingType(FieldDescriptor field) {
|
||||
if (field.getContainingType() != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"FieldDescriptor does not match message type.");
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/**
|
||||
* Builder for {@link DynamicMessage}s.
|
||||
*/
|
||||
public static final class Builder extends AbstractMessage.Builder<Builder> {
|
||||
private final Descriptor type;
|
||||
private FieldSet<FieldDescriptor> fields;
|
||||
private UnknownFieldSet unknownFields;
|
||||
|
||||
/** Construct a {@code Builder} for the given type. */
|
||||
private Builder(Descriptor type) {
|
||||
this.type = type;
|
||||
this.fields = FieldSet.newFieldSet();
|
||||
this.unknownFields = UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Implementation of Message.Builder interface.
|
||||
|
||||
@Override
|
||||
public Builder clear() {
|
||||
if (fields == null) {
|
||||
throw new IllegalStateException("Cannot call clear() after build().");
|
||||
}
|
||||
fields.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(Message other) {
|
||||
if (other instanceof DynamicMessage) {
|
||||
// This should be somewhat faster than calling super.mergeFrom().
|
||||
DynamicMessage otherDynamicMessage = (DynamicMessage) other;
|
||||
if (otherDynamicMessage.type != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"mergeFrom(Message) can only merge messages of the same type.");
|
||||
}
|
||||
fields.mergeFrom(otherDynamicMessage.fields);
|
||||
mergeUnknownFields(otherDynamicMessage.unknownFields);
|
||||
return this;
|
||||
} else {
|
||||
return super.mergeFrom(other);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage build() {
|
||||
// If fields == null, we'll throw an appropriate exception later.
|
||||
if (fields != null && !isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
new DynamicMessage(type, fields, unknownFields));
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for DynamicMessage.parseFrom() methods to call. Throws
|
||||
* {@link InvalidProtocolBufferException} instead of
|
||||
* {@link UninitializedMessageException}.
|
||||
*/
|
||||
private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
new DynamicMessage(type, fields, unknownFields))
|
||||
.asInvalidProtocolBufferException();
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage buildPartial() {
|
||||
if (fields == null) {
|
||||
throw new IllegalStateException(
|
||||
"build() has already been called on this Builder.");
|
||||
}
|
||||
fields.makeImmutable();
|
||||
DynamicMessage result =
|
||||
new DynamicMessage(type, fields, unknownFields);
|
||||
fields = null;
|
||||
unknownFields = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clone() {
|
||||
Builder result = new Builder(type);
|
||||
result.fields.mergeFrom(fields);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return DynamicMessage.isInitialized(type, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Descriptor getDescriptorForType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMessage getDefaultInstanceForType() {
|
||||
return getDefaultInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<FieldDescriptor, Object> getAllFields() {
|
||||
return fields.getAllFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
|
||||
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"newBuilderForField is only valid for fields with message type.");
|
||||
}
|
||||
|
||||
return new Builder(field.getMessageType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.hasField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
Object result = fields.getField(field);
|
||||
if (result == null) {
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
result = getDefaultInstance(field.getMessageType());
|
||||
} else {
|
||||
result = field.getDefaultValue();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setField(FieldDescriptor field, Object value) {
|
||||
verifyContainingType(field);
|
||||
fields.setField(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clearField(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
fields.clearField(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatedFieldCount(FieldDescriptor field) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedFieldCount(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRepeatedField(FieldDescriptor field, int index) {
|
||||
verifyContainingType(field);
|
||||
return fields.getRepeatedField(field, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setRepeatedField(FieldDescriptor field,
|
||||
int index, Object value) {
|
||||
verifyContainingType(field);
|
||||
fields.setRepeatedField(field, index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder addRepeatedField(FieldDescriptor field, Object value) {
|
||||
verifyContainingType(field);
|
||||
fields.addRepeatedField(field, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getUnknownFields() {
|
||||
return unknownFields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
|
||||
this.unknownFields = unknownFields;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
|
||||
this.unknownFields =
|
||||
UnknownFieldSet.newBuilder(this.unknownFields)
|
||||
.mergeFrom(unknownFields)
|
||||
.build();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Verifies that the field is a field of this message. */
|
||||
private void verifyContainingType(FieldDescriptor field) {
|
||||
if (field.getContainingType() != type) {
|
||||
throw new IllegalArgumentException(
|
||||
"FieldDescriptor does not match message type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
266
OsmAnd-java/src/com/google/protobuf/ExtensionRegistry.java
Normal file
266
OsmAnd-java/src/com/google/protobuf/ExtensionRegistry.java
Normal file
|
@ -0,0 +1,266 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
|
||||
/**
|
||||
* A table of known extensions, searchable by name or field number. When
|
||||
* parsing a protocol message that might have extensions, you must provide
|
||||
* an {@code ExtensionRegistry} in which you have registered any extensions
|
||||
* that you want to be able to parse. Otherwise, those extensions will just
|
||||
* be treated like unknown fields.
|
||||
*
|
||||
* <p>For example, if you had the {@code .proto} file:
|
||||
*
|
||||
* <pre>
|
||||
* option java_class = "MyProto";
|
||||
*
|
||||
* message Foo {
|
||||
* extensions 1000 to max;
|
||||
* }
|
||||
*
|
||||
* extend Foo {
|
||||
* optional int32 bar;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Then you might write code like:
|
||||
*
|
||||
* <pre>
|
||||
* ExtensionRegistry registry = ExtensionRegistry.newInstance();
|
||||
* registry.add(MyProto.bar);
|
||||
* MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
|
||||
* </pre>
|
||||
*
|
||||
* <p>Background:
|
||||
*
|
||||
* <p>You might wonder why this is necessary. Two alternatives might come to
|
||||
* mind. First, you might imagine a system where generated extensions are
|
||||
* automatically registered when their containing classes are loaded. This
|
||||
* is a popular technique, but is bad design; among other things, it creates a
|
||||
* situation where behavior can change depending on what classes happen to be
|
||||
* loaded. It also introduces a security vulnerability, because an
|
||||
* unprivileged class could cause its code to be called unexpectedly from a
|
||||
* privileged class by registering itself as an extension of the right type.
|
||||
*
|
||||
* <p>Another option you might consider is lazy parsing: do not parse an
|
||||
* extension until it is first requested, at which point the caller must
|
||||
* provide a type to use. This introduces a different set of problems. First,
|
||||
* it would require a mutex lock any time an extension was accessed, which
|
||||
* would be slow. Second, corrupt data would not be detected until first
|
||||
* access, at which point it would be much harder to deal with it. Third, it
|
||||
* could violate the expectation that message objects are immutable, since the
|
||||
* type provided could be any arbitrary message class. An unprivileged user
|
||||
* could take advantage of this to inject a mutable object into a message
|
||||
* belonging to privileged code and create mischief.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class ExtensionRegistry extends ExtensionRegistryLite {
|
||||
/** Construct a new, empty instance. */
|
||||
public static ExtensionRegistry newInstance() {
|
||||
return new ExtensionRegistry();
|
||||
}
|
||||
|
||||
/** Get the unmodifiable singleton empty instance. */
|
||||
public static ExtensionRegistry getEmptyRegistry() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/** Returns an unmodifiable view of the registry. */
|
||||
@Override
|
||||
public ExtensionRegistry getUnmodifiable() {
|
||||
return new ExtensionRegistry(this);
|
||||
}
|
||||
|
||||
/** A (Descriptor, Message) pair, returned by lookup methods. */
|
||||
public static final class ExtensionInfo {
|
||||
/** The extension's descriptor. */
|
||||
public final FieldDescriptor descriptor;
|
||||
|
||||
/**
|
||||
* A default instance of the extension's type, if it has a message type.
|
||||
* Otherwise, {@code null}.
|
||||
*/
|
||||
public final Message defaultInstance;
|
||||
|
||||
private ExtensionInfo(final FieldDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
defaultInstance = null;
|
||||
}
|
||||
private ExtensionInfo(final FieldDescriptor descriptor,
|
||||
final Message defaultInstance) {
|
||||
this.descriptor = descriptor;
|
||||
this.defaultInstance = defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by fully-qualified field name, in the proto namespace.
|
||||
* I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
|
||||
* a match is found.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
public ExtensionInfo findExtensionByName(final String fullName) {
|
||||
return extensionsByName.get(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by containing type and field number.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
|
||||
final int fieldNumber) {
|
||||
return extensionsByNumber.get(
|
||||
new DescriptorIntPair(containingType, fieldNumber));
|
||||
}
|
||||
|
||||
/** Add an extension from a generated file to the registry. */
|
||||
public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
|
||||
if (extension.getDescriptor().getJavaType() ==
|
||||
FieldDescriptor.JavaType.MESSAGE) {
|
||||
if (extension.getMessageDefaultInstance() == null) {
|
||||
throw new IllegalStateException(
|
||||
"Registered message-type extension had null default instance: " +
|
||||
extension.getDescriptor().getFullName());
|
||||
}
|
||||
add(new ExtensionInfo(extension.getDescriptor(),
|
||||
extension.getMessageDefaultInstance()));
|
||||
} else {
|
||||
add(new ExtensionInfo(extension.getDescriptor(), null));
|
||||
}
|
||||
}
|
||||
|
||||
/** Add a non-message-type extension to the registry by descriptor. */
|
||||
public void add(final FieldDescriptor type) {
|
||||
if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"ExtensionRegistry.add() must be provided a default instance when " +
|
||||
"adding an embedded message extension.");
|
||||
}
|
||||
add(new ExtensionInfo(type, null));
|
||||
}
|
||||
|
||||
/** Add a message-type extension to the registry by descriptor. */
|
||||
public void add(final FieldDescriptor type, final Message defaultInstance) {
|
||||
if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"ExtensionRegistry.add() provided a default instance for a " +
|
||||
"non-message extension.");
|
||||
}
|
||||
add(new ExtensionInfo(type, defaultInstance));
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Private stuff.
|
||||
|
||||
private ExtensionRegistry() {
|
||||
this.extensionsByName = new HashMap<String, ExtensionInfo>();
|
||||
this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
|
||||
}
|
||||
|
||||
private ExtensionRegistry(ExtensionRegistry other) {
|
||||
super(other);
|
||||
this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
|
||||
this.extensionsByNumber =
|
||||
Collections.unmodifiableMap(other.extensionsByNumber);
|
||||
}
|
||||
|
||||
private final Map<String, ExtensionInfo> extensionsByName;
|
||||
private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
|
||||
|
||||
private ExtensionRegistry(boolean empty) {
|
||||
super(ExtensionRegistryLite.getEmptyRegistry());
|
||||
this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
|
||||
this.extensionsByNumber =
|
||||
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
|
||||
}
|
||||
private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
|
||||
|
||||
private void add(final ExtensionInfo extension) {
|
||||
if (!extension.descriptor.isExtension()) {
|
||||
throw new IllegalArgumentException(
|
||||
"ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
|
||||
"(non-extension) field.");
|
||||
}
|
||||
|
||||
extensionsByName.put(extension.descriptor.getFullName(), extension);
|
||||
extensionsByNumber.put(
|
||||
new DescriptorIntPair(extension.descriptor.getContainingType(),
|
||||
extension.descriptor.getNumber()),
|
||||
extension);
|
||||
|
||||
final FieldDescriptor field = extension.descriptor;
|
||||
if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
|
||||
field.getType() == FieldDescriptor.Type.MESSAGE &&
|
||||
field.isOptional() &&
|
||||
field.getExtensionScope() == field.getMessageType()) {
|
||||
// This is an extension of a MessageSet type defined within the extension
|
||||
// type's own scope. For backwards-compatibility, allow it to be looked
|
||||
// up by type name.
|
||||
extensionsByName.put(field.getMessageType().getFullName(), extension);
|
||||
}
|
||||
}
|
||||
|
||||
/** A (GenericDescriptor, int) pair, used as a map key. */
|
||||
private static final class DescriptorIntPair {
|
||||
private final Descriptor descriptor;
|
||||
private final int number;
|
||||
|
||||
DescriptorIntPair(final Descriptor descriptor, final int number) {
|
||||
this.descriptor = descriptor;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return descriptor.hashCode() * ((1 << 16) - 1) + number;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof DescriptorIntPair)) {
|
||||
return false;
|
||||
}
|
||||
final DescriptorIntPair other = (DescriptorIntPair)obj;
|
||||
return descriptor == other.descriptor && number == other.number;
|
||||
}
|
||||
}
|
||||
}
|
169
OsmAnd-java/src/com/google/protobuf/ExtensionRegistryLite.java
Normal file
169
OsmAnd-java/src/com/google/protobuf/ExtensionRegistryLite.java
Normal file
|
@ -0,0 +1,169 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
|
||||
* <p>
|
||||
* If all of your types are lite types, then you only need to use
|
||||
* {@code ExtensionRegistryLite}. Similarly, if all your types are regular
|
||||
* types, then you only need {@link ExtensionRegistry}. Typically it does not
|
||||
* make sense to mix the two, since if you have any regular types in your
|
||||
* program, you then require the full runtime and lose all the benefits of
|
||||
* the lite runtime, so you might as well make all your types be regular types.
|
||||
* However, in some cases (e.g. when depending on multiple third-patry libraries
|
||||
* where one uses lite types and one uses regular), you may find yourself
|
||||
* wanting to mix the two. In this case things get more complicated.
|
||||
* <p>
|
||||
* There are three factors to consider: Whether the type being extended is
|
||||
* lite, whether the embedded type (in the case of a message-typed extension)
|
||||
* is lite, and whether the extension itself is lite. Since all three are
|
||||
* declared in different files, they could all be different. Here are all
|
||||
* the combinations and which type of registry to use:
|
||||
* <pre>
|
||||
* Extended type Inner type Extension Use registry
|
||||
* =======================================================================
|
||||
* lite lite lite ExtensionRegistryLite
|
||||
* lite regular lite ExtensionRegistry
|
||||
* regular regular regular ExtensionRegistry
|
||||
* all other combinations not supported
|
||||
* </pre>
|
||||
* <p>
|
||||
* Note that just as regular types are not allowed to contain lite-type fields,
|
||||
* they are also not allowed to contain lite-type extensions. This is because
|
||||
* regular types must be fully accessible via reflection, which in turn means
|
||||
* that all the inner messages must also support reflection. On the other hand,
|
||||
* since regular types implement the entire lite interface, there is no problem
|
||||
* with embedding regular types inside lite types.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public class ExtensionRegistryLite {
|
||||
/** Construct a new, empty instance. */
|
||||
public static ExtensionRegistryLite newInstance() {
|
||||
return new ExtensionRegistryLite();
|
||||
}
|
||||
|
||||
/** Get the unmodifiable singleton empty instance. */
|
||||
public static ExtensionRegistryLite getEmptyRegistry() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/** Returns an unmodifiable view of the registry. */
|
||||
public ExtensionRegistryLite getUnmodifiable() {
|
||||
return new ExtensionRegistryLite(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an extension by containing type and field number.
|
||||
*
|
||||
* @return Information about the extension if found, or {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <ContainingType extends MessageLite>
|
||||
GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
|
||||
findLiteExtensionByNumber(
|
||||
final ContainingType containingTypeDefaultInstance,
|
||||
final int fieldNumber) {
|
||||
return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
|
||||
extensionsByNumber.get(
|
||||
new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
|
||||
}
|
||||
|
||||
/** Add an extension from a lite generated file to the registry. */
|
||||
public final void add(
|
||||
final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
|
||||
extensionsByNumber.put(
|
||||
new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
|
||||
extension.getNumber()),
|
||||
extension);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Private stuff.
|
||||
|
||||
// Constructors are package-private so that ExtensionRegistry can subclass
|
||||
// this.
|
||||
|
||||
ExtensionRegistryLite() {
|
||||
this.extensionsByNumber =
|
||||
new HashMap<ObjectIntPair,
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?>>();
|
||||
}
|
||||
|
||||
ExtensionRegistryLite(ExtensionRegistryLite other) {
|
||||
if (other == EMPTY) {
|
||||
this.extensionsByNumber = Collections.emptyMap();
|
||||
} else {
|
||||
this.extensionsByNumber =
|
||||
Collections.unmodifiableMap(other.extensionsByNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<ObjectIntPair,
|
||||
GeneratedMessageLite.GeneratedExtension<?, ?>>
|
||||
extensionsByNumber;
|
||||
|
||||
private ExtensionRegistryLite(boolean empty) {
|
||||
this.extensionsByNumber = Collections.emptyMap();
|
||||
}
|
||||
private static final ExtensionRegistryLite EMPTY =
|
||||
new ExtensionRegistryLite(true);
|
||||
|
||||
/** A (Object, int) pair, used as a map key. */
|
||||
private static final class ObjectIntPair {
|
||||
private final Object object;
|
||||
private final int number;
|
||||
|
||||
ObjectIntPair(final Object object, final int number) {
|
||||
this.object = object;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(object) * ((1 << 16) - 1) + number;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof ObjectIntPair)) {
|
||||
return false;
|
||||
}
|
||||
final ObjectIntPair other = (ObjectIntPair)obj;
|
||||
return object == other.object && number == other.number;
|
||||
}
|
||||
}
|
||||
}
|
715
OsmAnd-java/src/com/google/protobuf/FieldSet.java
Normal file
715
OsmAnd-java/src/com/google/protobuf/FieldSet.java
Normal file
|
@ -0,0 +1,715 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* A class which represents an arbitrary set of fields of some message type.
|
||||
* This is used to implement {@link DynamicMessage}, and also to represent
|
||||
* extensions in {@link GeneratedMessage}. This class is package-private,
|
||||
* since outside users should probably be using {@link DynamicMessage}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
final class FieldSet<FieldDescriptorType extends
|
||||
FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
|
||||
/**
|
||||
* Interface for a FieldDescriptor or lite extension descriptor. This
|
||||
* prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
|
||||
*/
|
||||
public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
|
||||
extends Comparable<T> {
|
||||
int getNumber();
|
||||
WireFormat.FieldType getLiteType();
|
||||
WireFormat.JavaType getLiteJavaType();
|
||||
boolean isRepeated();
|
||||
boolean isPacked();
|
||||
Internal.EnumLiteMap<?> getEnumType();
|
||||
|
||||
// If getLiteJavaType() == MESSAGE, this merges a message object of the
|
||||
// type into a builder of the type. Returns {@code to}.
|
||||
MessageLite.Builder internalMergeFrom(
|
||||
MessageLite.Builder to, MessageLite from);
|
||||
}
|
||||
|
||||
private Map<FieldDescriptorType, Object> fields;
|
||||
|
||||
/** Construct a new FieldSet. */
|
||||
private FieldSet() {
|
||||
// Use a TreeMap because fields need to be in canonical order when
|
||||
// serializing.
|
||||
// TODO(kenton): Maybe use some sort of sparse array instead? It would
|
||||
// even make sense to store the first 16 or so tags in a flat array
|
||||
// to make DynamicMessage faster.
|
||||
fields = new TreeMap<FieldDescriptorType, Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an empty FieldSet. This is only used to initialize
|
||||
* DEFAULT_INSTANCE.
|
||||
*/
|
||||
private FieldSet(final boolean dummy) {
|
||||
this.fields = Collections.emptyMap();
|
||||
}
|
||||
|
||||
/** Construct a new FieldSet. */
|
||||
public static <T extends FieldSet.FieldDescriptorLite<T>>
|
||||
FieldSet<T> newFieldSet() {
|
||||
return new FieldSet<T>();
|
||||
}
|
||||
|
||||
/** Get an immutable empty FieldSet. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends FieldSet.FieldDescriptorLite<T>>
|
||||
FieldSet<T> emptySet() {
|
||||
return DEFAULT_INSTANCE;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
|
||||
|
||||
/** Make this FieldSet immutable from this point forward. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public void makeImmutable() {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
fields.entrySet()) {
|
||||
if (entry.getKey().isRepeated()) {
|
||||
final List value = (List)entry.getValue();
|
||||
fields.put(entry.getKey(), Collections.unmodifiableList(value));
|
||||
}
|
||||
}
|
||||
fields = Collections.unmodifiableMap(fields);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
|
||||
/** See {@link Message.Builder#clear()}. */
|
||||
public void clear() {
|
||||
fields.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a simple map containing all the fields.
|
||||
*/
|
||||
public Map<FieldDescriptorType, Object> getAllFields() {
|
||||
return Collections.unmodifiableMap(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator to the field map. This iterator should not be leaked
|
||||
* out of the protobuf library as it is not protected from mutation.
|
||||
*/
|
||||
public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
|
||||
return fields.entrySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#hasField(Descriptors.FieldDescriptor)}.
|
||||
*/
|
||||
public boolean hasField(final FieldDescriptorType descriptor) {
|
||||
if (descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"hasField() can only be called on non-repeated fields.");
|
||||
}
|
||||
|
||||
return fields.get(descriptor) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)}. This method
|
||||
* returns {@code null} if the field is not set; in this case it is up
|
||||
* to the caller to fetch the field's default value.
|
||||
*/
|
||||
public Object getField(final FieldDescriptorType descriptor) {
|
||||
return fields.get(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setField(final FieldDescriptorType descriptor,
|
||||
Object value) {
|
||||
if (descriptor.isRepeated()) {
|
||||
if (!(value instanceof List)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Wrong object type used with protocol message reflection.");
|
||||
}
|
||||
|
||||
// Wrap the contents in a new list so that the caller cannot change
|
||||
// the list's contents after setting it.
|
||||
final List newList = new ArrayList();
|
||||
newList.addAll((List)value);
|
||||
for (final Object element : newList) {
|
||||
verifyType(descriptor.getLiteType(), element);
|
||||
}
|
||||
value = newList;
|
||||
} else {
|
||||
verifyType(descriptor.getLiteType(), value);
|
||||
}
|
||||
|
||||
fields.put(descriptor, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
|
||||
*/
|
||||
public void clearField(final FieldDescriptorType descriptor) {
|
||||
fields.remove(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
|
||||
*/
|
||||
public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
final Object value = fields.get(descriptor);
|
||||
if (value == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((List<?>) value).size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getRepeatedField(final FieldDescriptorType descriptor,
|
||||
final int index) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
final Object value = fields.get(descriptor);
|
||||
|
||||
if (value == null) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else {
|
||||
return ((List) value).get(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setRepeatedField(final FieldDescriptorType descriptor,
|
||||
final int index,
|
||||
final Object value) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"getRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
final Object list = fields.get(descriptor);
|
||||
if (list == null) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
verifyType(descriptor.getLiteType(), value);
|
||||
((List) list).set(index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful for implementing
|
||||
* {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addRepeatedField(final FieldDescriptorType descriptor,
|
||||
final Object value) {
|
||||
if (!descriptor.isRepeated()) {
|
||||
throw new IllegalArgumentException(
|
||||
"addRepeatedField() can only be called on repeated fields.");
|
||||
}
|
||||
|
||||
verifyType(descriptor.getLiteType(), value);
|
||||
|
||||
final Object existingValue = fields.get(descriptor);
|
||||
List list;
|
||||
if (existingValue == null) {
|
||||
list = new ArrayList();
|
||||
fields.put(descriptor, list);
|
||||
} else {
|
||||
list = (List) existingValue;
|
||||
}
|
||||
|
||||
list.add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the given object is of the correct type to be a valid
|
||||
* value for the given field. (For repeated fields, this checks if the
|
||||
* object is the right type to be one element of the field.)
|
||||
*
|
||||
* @throws IllegalArgumentException The value is not of the right type.
|
||||
*/
|
||||
private static void verifyType(final WireFormat.FieldType type,
|
||||
final Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
boolean isValid = false;
|
||||
switch (type.getJavaType()) {
|
||||
case INT: isValid = value instanceof Integer ; break;
|
||||
case LONG: isValid = value instanceof Long ; break;
|
||||
case FLOAT: isValid = value instanceof Float ; break;
|
||||
case DOUBLE: isValid = value instanceof Double ; break;
|
||||
case BOOLEAN: isValid = value instanceof Boolean ; break;
|
||||
case STRING: isValid = value instanceof String ; break;
|
||||
case BYTE_STRING: isValid = value instanceof ByteString; break;
|
||||
case ENUM:
|
||||
// TODO(kenton): Caller must do type checking here, I guess.
|
||||
isValid = value instanceof Internal.EnumLite;
|
||||
break;
|
||||
case MESSAGE:
|
||||
// TODO(kenton): Caller must do type checking here, I guess.
|
||||
isValid = value instanceof MessageLite;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
// TODO(kenton): When chaining calls to setField(), it can be hard to
|
||||
// tell from the stack trace which exact call failed, since the whole
|
||||
// chain is considered one line of code. It would be nice to print
|
||||
// more information here, e.g. naming the field. We used to do that.
|
||||
// But we can't now that FieldSet doesn't use descriptors. Maybe this
|
||||
// isn't a big deal, though, since it would only really apply when using
|
||||
// reflection and generally people don't chain reflection setters.
|
||||
throw new IllegalArgumentException(
|
||||
"Wrong object type used with protocol message reflection.");
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Parsing and serialization
|
||||
|
||||
/**
|
||||
* See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
|
||||
* itself does not have any way of knowing about required fields that
|
||||
* aren't actually present in the set, it is up to the caller to check
|
||||
* that all required fields are present.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean isInitialized() {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
fields.entrySet()) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
|
||||
if (descriptor.isRepeated()) {
|
||||
for (final MessageLite element:
|
||||
(List<MessageLite>) entry.getValue()) {
|
||||
if (!element.isInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!((MessageLite) entry.getValue()).isInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a field type, return the wire type.
|
||||
*
|
||||
* @returns One of the {@code WIRETYPE_} constants defined in
|
||||
* {@link WireFormat}.
|
||||
*/
|
||||
static int getWireFormatForFieldType(final WireFormat.FieldType type,
|
||||
boolean isPacked) {
|
||||
if (isPacked) {
|
||||
return WireFormat.WIRETYPE_LENGTH_DELIMITED;
|
||||
} else {
|
||||
return type.getWireType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
other.fields.entrySet()) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
final Object otherValue = entry.getValue();
|
||||
|
||||
if (descriptor.isRepeated()) {
|
||||
Object value = fields.get(descriptor);
|
||||
if (value == null) {
|
||||
// Our list is empty, but we still need to make a defensive copy of
|
||||
// the other list since we don't know if the other FieldSet is still
|
||||
// mutable.
|
||||
fields.put(descriptor, new ArrayList((List) otherValue));
|
||||
} else {
|
||||
// Concatenate the lists.
|
||||
((List) value).addAll((List) otherValue);
|
||||
}
|
||||
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
|
||||
Object value = fields.get(descriptor);
|
||||
if (value == null) {
|
||||
fields.put(descriptor, otherValue);
|
||||
} else {
|
||||
// Merge the messages.
|
||||
fields.put(descriptor,
|
||||
descriptor.internalMergeFrom(
|
||||
((MessageLite) value).toBuilder(), (MessageLite) otherValue)
|
||||
.build());
|
||||
}
|
||||
|
||||
} else {
|
||||
fields.put(descriptor, otherValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(kenton): Move static parsing and serialization methods into some
|
||||
// other class. Probably WireFormat.
|
||||
|
||||
/**
|
||||
* Read a field of any primitive type from a CodedInputStream. Enums,
|
||||
* groups, and embedded messages are not handled by this method.
|
||||
*
|
||||
* @param input The stream from which to read.
|
||||
* @param type Declared type of the field.
|
||||
* @return An object representing the field's value, of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
*/
|
||||
public static Object readPrimitiveField(
|
||||
CodedInputStream input,
|
||||
final WireFormat.FieldType type) throws IOException {
|
||||
switch (type) {
|
||||
case DOUBLE : return input.readDouble ();
|
||||
case FLOAT : return input.readFloat ();
|
||||
case INT64 : return input.readInt64 ();
|
||||
case UINT64 : return input.readUInt64 ();
|
||||
case INT32 : return input.readInt32 ();
|
||||
case FIXED64 : return input.readFixed64 ();
|
||||
case FIXED32 : return input.readFixed32 ();
|
||||
case BOOL : return input.readBool ();
|
||||
case STRING : return input.readString ();
|
||||
case BYTES : return input.readBytes ();
|
||||
case UINT32 : return input.readUInt32 ();
|
||||
case SFIXED32: return input.readSFixed32();
|
||||
case SFIXED64: return input.readSFixed64();
|
||||
case SINT32 : return input.readSInt32 ();
|
||||
case SINT64 : return input.readSInt64 ();
|
||||
|
||||
case GROUP:
|
||||
throw new IllegalArgumentException(
|
||||
"readPrimitiveField() cannot handle nested groups.");
|
||||
case MESSAGE:
|
||||
throw new IllegalArgumentException(
|
||||
"readPrimitiveField() cannot handle embedded messages.");
|
||||
case ENUM:
|
||||
// We don't handle enums because we don't know what to do if the
|
||||
// value is not recognized.
|
||||
throw new IllegalArgumentException(
|
||||
"readPrimitiveField() cannot handle enums.");
|
||||
}
|
||||
|
||||
throw new RuntimeException(
|
||||
"There is no way to get here, but the compiler thinks otherwise.");
|
||||
}
|
||||
|
||||
/** See {@link Message#writeTo(CodedOutputStream)}. */
|
||||
public void writeTo(final CodedOutputStream output)
|
||||
throws IOException {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
fields.entrySet()) {
|
||||
writeField(entry.getKey(), entry.getValue(), output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #writeTo} but uses MessageSet wire format.
|
||||
*/
|
||||
public void writeMessageSetTo(final CodedOutputStream output)
|
||||
throws IOException {
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
fields.entrySet()) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
|
||||
!descriptor.isRepeated() && !descriptor.isPacked()) {
|
||||
output.writeMessageSetExtension(entry.getKey().getNumber(),
|
||||
(MessageLite) entry.getValue());
|
||||
} else {
|
||||
writeField(descriptor, entry.getValue(), output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single tag-value pair to the stream.
|
||||
*
|
||||
* @param output The output stream.
|
||||
* @param type The field's type.
|
||||
* @param number The field's number.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
*/
|
||||
private static void writeElement(final CodedOutputStream output,
|
||||
final WireFormat.FieldType type,
|
||||
final int number,
|
||||
final Object value) throws IOException {
|
||||
// Special case for groups, which need a start and end tag; other fields
|
||||
// can just use writeTag() and writeFieldNoTag().
|
||||
if (type == WireFormat.FieldType.GROUP) {
|
||||
output.writeGroup(number, (MessageLite) value);
|
||||
} else {
|
||||
output.writeTag(number, getWireFormatForFieldType(type, false));
|
||||
writeElementNoTag(output, type, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a field of arbitrary type, without its tag, to the stream.
|
||||
*
|
||||
* @param output The output stream.
|
||||
* @param type The field's type.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
*/
|
||||
private static void writeElementNoTag(
|
||||
final CodedOutputStream output,
|
||||
final WireFormat.FieldType type,
|
||||
final Object value) throws IOException {
|
||||
switch (type) {
|
||||
case DOUBLE : output.writeDoubleNoTag ((Double ) value); break;
|
||||
case FLOAT : output.writeFloatNoTag ((Float ) value); break;
|
||||
case INT64 : output.writeInt64NoTag ((Long ) value); break;
|
||||
case UINT64 : output.writeUInt64NoTag ((Long ) value); break;
|
||||
case INT32 : output.writeInt32NoTag ((Integer ) value); break;
|
||||
case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
|
||||
case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
|
||||
case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
|
||||
case STRING : output.writeStringNoTag ((String ) value); break;
|
||||
case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
|
||||
case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
|
||||
case BYTES : output.writeBytesNoTag ((ByteString ) value); break;
|
||||
case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
|
||||
case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
|
||||
case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
|
||||
case SINT32 : output.writeSInt32NoTag ((Integer ) value); break;
|
||||
case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
|
||||
|
||||
case ENUM:
|
||||
output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Write a single field. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void writeField(final FieldDescriptorLite<?> descriptor,
|
||||
final Object value,
|
||||
final CodedOutputStream output)
|
||||
throws IOException {
|
||||
WireFormat.FieldType type = descriptor.getLiteType();
|
||||
int number = descriptor.getNumber();
|
||||
if (descriptor.isRepeated()) {
|
||||
final List valueList = (List)value;
|
||||
if (descriptor.isPacked()) {
|
||||
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
||||
// Compute the total data size so the length can be written.
|
||||
int dataSize = 0;
|
||||
for (final Object element : valueList) {
|
||||
dataSize += computeElementSizeNoTag(type, element);
|
||||
}
|
||||
output.writeRawVarint32(dataSize);
|
||||
// Write the data itself, without any tags.
|
||||
for (final Object element : valueList) {
|
||||
writeElementNoTag(output, type, element);
|
||||
}
|
||||
} else {
|
||||
for (final Object element : valueList) {
|
||||
writeElement(output, type, number, element);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
writeElement(output, type, number, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link Message#getSerializedSize()}. It's up to the caller to cache
|
||||
* the resulting size if desired.
|
||||
*/
|
||||
public int getSerializedSize() {
|
||||
int size = 0;
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
fields.entrySet()) {
|
||||
size += computeFieldSize(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #getSerializedSize} but uses MessageSet wire format.
|
||||
*/
|
||||
public int getMessageSetSerializedSize() {
|
||||
int size = 0;
|
||||
for (final Map.Entry<FieldDescriptorType, Object> entry:
|
||||
fields.entrySet()) {
|
||||
final FieldDescriptorType descriptor = entry.getKey();
|
||||
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
|
||||
!descriptor.isRepeated() && !descriptor.isPacked()) {
|
||||
size += CodedOutputStream.computeMessageSetExtensionSize(
|
||||
entry.getKey().getNumber(), (MessageLite) entry.getValue());
|
||||
} else {
|
||||
size += computeFieldSize(descriptor, entry.getValue());
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* single tag/value pair of arbitrary type.
|
||||
*
|
||||
* @param type The field's type.
|
||||
* @param number The field's number.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
*/
|
||||
private static int computeElementSize(
|
||||
final WireFormat.FieldType type,
|
||||
final int number, final Object value) {
|
||||
int tagSize = CodedOutputStream.computeTagSize(number);
|
||||
if (type == WireFormat.FieldType.GROUP) {
|
||||
tagSize *= 2;
|
||||
}
|
||||
return tagSize + computeElementSizeNoTag(type, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes that would be needed to encode a
|
||||
* particular value of arbitrary type, excluding tag.
|
||||
*
|
||||
* @param type The field's type.
|
||||
* @param value Object representing the field's value. Must be of the exact
|
||||
* type which would be returned by
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} for
|
||||
* this field.
|
||||
*/
|
||||
private static int computeElementSizeNoTag(
|
||||
final WireFormat.FieldType type, final Object value) {
|
||||
switch (type) {
|
||||
// Note: Minor violation of 80-char limit rule here because this would
|
||||
// actually be harder to read if we wrapped the lines.
|
||||
case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value);
|
||||
case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value);
|
||||
case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value);
|
||||
case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value);
|
||||
case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value);
|
||||
case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
|
||||
case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
|
||||
case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
|
||||
case STRING : return CodedOutputStream.computeStringSizeNoTag ((String )value);
|
||||
case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
|
||||
case MESSAGE : return CodedOutputStream.computeMessageSizeNoTag ((MessageLite)value);
|
||||
case BYTES : return CodedOutputStream.computeBytesSizeNoTag ((ByteString )value);
|
||||
case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
|
||||
case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
|
||||
case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
|
||||
case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
|
||||
case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
|
||||
|
||||
case ENUM:
|
||||
return CodedOutputStream.computeEnumSizeNoTag(
|
||||
((Internal.EnumLite) value).getNumber());
|
||||
}
|
||||
|
||||
throw new RuntimeException(
|
||||
"There is no way to get here, but the compiler thinks otherwise.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of bytes needed to encode a particular field.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
|
||||
final Object value) {
|
||||
WireFormat.FieldType type = descriptor.getLiteType();
|
||||
int number = descriptor.getNumber();
|
||||
if (descriptor.isRepeated()) {
|
||||
if (descriptor.isPacked()) {
|
||||
int dataSize = 0;
|
||||
for (final Object element : (List)value) {
|
||||
dataSize += computeElementSizeNoTag(type, element);
|
||||
}
|
||||
return dataSize +
|
||||
CodedOutputStream.computeTagSize(number) +
|
||||
CodedOutputStream.computeRawVarint32Size(dataSize);
|
||||
} else {
|
||||
int size = 0;
|
||||
for (final Object element : (List)value) {
|
||||
size += computeElementSize(type, number, element);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
} else {
|
||||
return computeElementSize(type, number, value);
|
||||
}
|
||||
}
|
||||
}
|
1370
OsmAnd-java/src/com/google/protobuf/GeneratedMessage.java
Normal file
1370
OsmAnd-java/src/com/google/protobuf/GeneratedMessage.java
Normal file
File diff suppressed because it is too large
Load diff
576
OsmAnd-java/src/com/google/protobuf/GeneratedMessageLite.java
Normal file
576
OsmAnd-java/src/com/google/protobuf/GeneratedMessageLite.java
Normal file
|
@ -0,0 +1,576 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Lite version of {@link GeneratedMessage}.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public abstract class GeneratedMessageLite extends AbstractMessageLite {
|
||||
protected GeneratedMessageLite() {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract static class Builder<MessageType extends GeneratedMessageLite,
|
||||
BuilderType extends Builder>
|
||||
extends AbstractMessageLite.Builder<BuilderType> {
|
||||
protected Builder() {}
|
||||
|
||||
// This is implemented here only to work around an apparent bug in the
|
||||
// Java compiler and/or build system. See bug #1898463. The mere presence
|
||||
// of this dummy clone() implementation makes it go away.
|
||||
@Override
|
||||
public BuilderType clone() {
|
||||
throw new UnsupportedOperationException(
|
||||
"This is supposed to be overridden by subclasses.");
|
||||
}
|
||||
|
||||
/** All subclasses implement this. */
|
||||
public abstract BuilderType mergeFrom(MessageType message);
|
||||
|
||||
// Defined here for return type covariance.
|
||||
@Override
|
||||
public abstract MessageType getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* Get the message being built. We don't just pass this to the
|
||||
* constructor because it becomes null when build() is called.
|
||||
*/
|
||||
protected abstract MessageType internalGetResult();
|
||||
|
||||
/**
|
||||
* Called by subclasses to parse an unknown field.
|
||||
* @return {@code true} unless the tag is an end-group tag.
|
||||
*/
|
||||
protected boolean parseUnknownField(
|
||||
final CodedInputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry,
|
||||
final int tag) throws IOException {
|
||||
return input.skipField(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// Extensions-related stuff
|
||||
|
||||
/**
|
||||
* Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
|
||||
*/
|
||||
public abstract static class ExtendableMessage<
|
||||
MessageType extends ExtendableMessage<MessageType>>
|
||||
extends GeneratedMessageLite {
|
||||
protected ExtendableMessage() {}
|
||||
private final FieldSet<ExtensionDescriptor> extensions =
|
||||
FieldSet.newFieldSet();
|
||||
|
||||
private void verifyExtensionContainingType(
|
||||
final GeneratedExtension<MessageType, ?> extension) {
|
||||
if (extension.getContainingTypeDefaultInstance() !=
|
||||
getDefaultInstanceForType()) {
|
||||
// This can only happen if someone uses unchecked operations.
|
||||
throw new IllegalArgumentException(
|
||||
"This extension is for a different message type. Please make " +
|
||||
"sure that you are not suppressing any generics type warnings.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a singular extension is present. */
|
||||
public final boolean hasExtension(
|
||||
final GeneratedExtension<MessageType, ?> extension) {
|
||||
verifyExtensionContainingType(extension);
|
||||
return extensions.hasField(extension.descriptor);
|
||||
}
|
||||
|
||||
/** Get the number of elements in a repeated extension. */
|
||||
public final <Type> int getExtensionCount(
|
||||
final GeneratedExtension<MessageType, List<Type>> extension) {
|
||||
verifyExtensionContainingType(extension);
|
||||
return extensions.getRepeatedFieldCount(extension.descriptor);
|
||||
}
|
||||
|
||||
/** Get the value of an extension. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <Type> Type getExtension(
|
||||
final GeneratedExtension<MessageType, Type> extension) {
|
||||
verifyExtensionContainingType(extension);
|
||||
final Object value = extensions.getField(extension.descriptor);
|
||||
if (value == null) {
|
||||
return extension.defaultValue;
|
||||
} else {
|
||||
return (Type) value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get one element of a repeated extension. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <Type> Type getExtension(
|
||||
final GeneratedExtension<MessageType, List<Type>> extension,
|
||||
final int index) {
|
||||
verifyExtensionContainingType(extension);
|
||||
return (Type) extensions.getRepeatedField(extension.descriptor, index);
|
||||
}
|
||||
|
||||
/** Called by subclasses to check if all extensions are initialized. */
|
||||
protected boolean extensionsAreInitialized() {
|
||||
return extensions.isInitialized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by subclasses to serialize extensions. Extension ranges may be
|
||||
* interleaved with field numbers, but we must write them in canonical
|
||||
* (sorted by field number) order. ExtensionWriter helps us write
|
||||
* individual ranges of extensions at once.
|
||||
*/
|
||||
protected class ExtensionWriter {
|
||||
// Imagine how much simpler this code would be if Java iterators had
|
||||
// a way to get the next element without advancing the iterator.
|
||||
|
||||
private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
|
||||
extensions.iterator();
|
||||
private Map.Entry<ExtensionDescriptor, Object> next;
|
||||
private final boolean messageSetWireFormat;
|
||||
|
||||
private ExtensionWriter(boolean messageSetWireFormat) {
|
||||
if (iter.hasNext()) {
|
||||
next = iter.next();
|
||||
}
|
||||
this.messageSetWireFormat = messageSetWireFormat;
|
||||
}
|
||||
|
||||
public void writeUntil(final int end, final CodedOutputStream output)
|
||||
throws IOException {
|
||||
while (next != null && next.getKey().getNumber() < end) {
|
||||
ExtensionDescriptor extension = next.getKey();
|
||||
if (messageSetWireFormat && extension.getLiteJavaType() ==
|
||||
WireFormat.JavaType.MESSAGE &&
|
||||
!extension.isRepeated()) {
|
||||
output.writeMessageSetExtension(extension.getNumber(),
|
||||
(MessageLite) next.getValue());
|
||||
} else {
|
||||
FieldSet.writeField(extension, next.getValue(), output);
|
||||
}
|
||||
if (iter.hasNext()) {
|
||||
next = iter.next();
|
||||
} else {
|
||||
next = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ExtensionWriter newExtensionWriter() {
|
||||
return new ExtensionWriter(false);
|
||||
}
|
||||
protected ExtensionWriter newMessageSetExtensionWriter() {
|
||||
return new ExtensionWriter(true);
|
||||
}
|
||||
|
||||
/** Called by subclasses to compute the size of extensions. */
|
||||
protected int extensionsSerializedSize() {
|
||||
return extensions.getSerializedSize();
|
||||
}
|
||||
protected int extensionsSerializedSizeAsMessageSet() {
|
||||
return extensions.getMessageSetSerializedSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract static class ExtendableBuilder<
|
||||
MessageType extends ExtendableMessage<MessageType>,
|
||||
BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
|
||||
extends Builder<MessageType, BuilderType> {
|
||||
protected ExtendableBuilder() {}
|
||||
|
||||
// This is implemented here only to work around an apparent bug in the
|
||||
// Java compiler and/or build system. See bug #1898463. The mere presence
|
||||
// of this dummy clone() implementation makes it go away.
|
||||
@Override
|
||||
public BuilderType clone() {
|
||||
throw new UnsupportedOperationException(
|
||||
"This is supposed to be overridden by subclasses.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract MessageType internalGetResult();
|
||||
|
||||
/** Check if a singular extension is present. */
|
||||
public final boolean hasExtension(
|
||||
final GeneratedExtension<MessageType, ?> extension) {
|
||||
return internalGetResult().hasExtension(extension);
|
||||
}
|
||||
|
||||
/** Get the number of elements in a repeated extension. */
|
||||
public final <Type> int getExtensionCount(
|
||||
final GeneratedExtension<MessageType, List<Type>> extension) {
|
||||
return internalGetResult().getExtensionCount(extension);
|
||||
}
|
||||
|
||||
/** Get the value of an extension. */
|
||||
public final <Type> Type getExtension(
|
||||
final GeneratedExtension<MessageType, Type> extension) {
|
||||
return internalGetResult().getExtension(extension);
|
||||
}
|
||||
|
||||
/** Get one element of a repeated extension. */
|
||||
public final <Type> Type getExtension(
|
||||
final GeneratedExtension<MessageType, List<Type>> extension,
|
||||
final int index) {
|
||||
return internalGetResult().getExtension(extension, index);
|
||||
}
|
||||
|
||||
/** Set the value of an extension. */
|
||||
public final <Type> BuilderType setExtension(
|
||||
final GeneratedExtension<MessageType, Type> extension,
|
||||
final Type value) {
|
||||
final ExtendableMessage<MessageType> message = internalGetResult();
|
||||
message.verifyExtensionContainingType(extension);
|
||||
message.extensions.setField(extension.descriptor, value);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/** Set the value of one element of a repeated extension. */
|
||||
public final <Type> BuilderType setExtension(
|
||||
final GeneratedExtension<MessageType, List<Type>> extension,
|
||||
final int index, final Type value) {
|
||||
final ExtendableMessage<MessageType> message = internalGetResult();
|
||||
message.verifyExtensionContainingType(extension);
|
||||
message.extensions.setRepeatedField(extension.descriptor, index, value);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/** Append a value to a repeated extension. */
|
||||
public final <Type> BuilderType addExtension(
|
||||
final GeneratedExtension<MessageType, List<Type>> extension,
|
||||
final Type value) {
|
||||
final ExtendableMessage<MessageType> message = internalGetResult();
|
||||
message.verifyExtensionContainingType(extension);
|
||||
message.extensions.addRepeatedField(extension.descriptor, value);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/** Clear an extension. */
|
||||
public final <Type> BuilderType clearExtension(
|
||||
final GeneratedExtension<MessageType, ?> extension) {
|
||||
final ExtendableMessage<MessageType> message = internalGetResult();
|
||||
message.verifyExtensionContainingType(extension);
|
||||
message.extensions.clearField(extension.descriptor);
|
||||
return (BuilderType) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by subclasses to parse an unknown field or an extension.
|
||||
* @return {@code true} unless the tag is an end-group tag.
|
||||
*/
|
||||
@Override
|
||||
protected boolean parseUnknownField(
|
||||
final CodedInputStream input,
|
||||
final ExtensionRegistryLite extensionRegistry,
|
||||
final int tag) throws IOException {
|
||||
final FieldSet<ExtensionDescriptor> extensions =
|
||||
((ExtendableMessage) internalGetResult()).extensions;
|
||||
|
||||
final int wireType = WireFormat.getTagWireType(tag);
|
||||
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
|
||||
|
||||
final GeneratedExtension<MessageType, ?> extension =
|
||||
extensionRegistry.findLiteExtensionByNumber(
|
||||
getDefaultInstanceForType(), fieldNumber);
|
||||
|
||||
boolean unknown = false;
|
||||
boolean packed = false;
|
||||
if (extension == null) {
|
||||
unknown = true; // Unknown field.
|
||||
} else if (wireType == FieldSet.getWireFormatForFieldType(
|
||||
extension.descriptor.getLiteType(),
|
||||
false /* isPacked */)) {
|
||||
packed = false; // Normal, unpacked value.
|
||||
} else if (extension.descriptor.isRepeated &&
|
||||
extension.descriptor.type.isPackable() &&
|
||||
wireType == FieldSet.getWireFormatForFieldType(
|
||||
extension.descriptor.getLiteType(),
|
||||
true /* isPacked */)) {
|
||||
packed = true; // Packed value.
|
||||
} else {
|
||||
unknown = true; // Wrong wire type.
|
||||
}
|
||||
|
||||
if (unknown) { // Unknown field or wrong wire type. Skip.
|
||||
return input.skipField(tag);
|
||||
}
|
||||
|
||||
if (packed) {
|
||||
final int length = input.readRawVarint32();
|
||||
final int limit = input.pushLimit(length);
|
||||
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
|
||||
while (input.getBytesUntilLimit() > 0) {
|
||||
final int rawValue = input.readEnum();
|
||||
final Object value =
|
||||
extension.descriptor.getEnumType().findValueByNumber(rawValue);
|
||||
if (value == null) {
|
||||
// If the number isn't recognized as a valid value for this
|
||||
// enum, drop it (don't even add it to unknownFields).
|
||||
return true;
|
||||
}
|
||||
extensions.addRepeatedField(extension.descriptor, value);
|
||||
}
|
||||
} else {
|
||||
while (input.getBytesUntilLimit() > 0) {
|
||||
final Object value =
|
||||
FieldSet.readPrimitiveField(input,
|
||||
extension.descriptor.getLiteType());
|
||||
extensions.addRepeatedField(extension.descriptor, value);
|
||||
}
|
||||
}
|
||||
input.popLimit(limit);
|
||||
} else {
|
||||
final Object value;
|
||||
switch (extension.descriptor.getLiteJavaType()) {
|
||||
case MESSAGE: {
|
||||
MessageLite.Builder subBuilder = null;
|
||||
if (!extension.descriptor.isRepeated()) {
|
||||
MessageLite existingValue =
|
||||
(MessageLite) extensions.getField(extension.descriptor);
|
||||
if (existingValue != null) {
|
||||
subBuilder = existingValue.toBuilder();
|
||||
}
|
||||
}
|
||||
if (subBuilder == null) {
|
||||
subBuilder = extension.messageDefaultInstance.newBuilderForType();
|
||||
}
|
||||
if (extension.descriptor.getLiteType() ==
|
||||
WireFormat.FieldType.GROUP) {
|
||||
input.readGroup(extension.getNumber(),
|
||||
subBuilder, extensionRegistry);
|
||||
} else {
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
}
|
||||
value = subBuilder.build();
|
||||
break;
|
||||
}
|
||||
case ENUM:
|
||||
final int rawValue = input.readEnum();
|
||||
value = extension.descriptor.getEnumType()
|
||||
.findValueByNumber(rawValue);
|
||||
// If the number isn't recognized as a valid value for this enum,
|
||||
// drop it.
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
value = FieldSet.readPrimitiveField(input,
|
||||
extension.descriptor.getLiteType());
|
||||
break;
|
||||
}
|
||||
|
||||
if (extension.descriptor.isRepeated()) {
|
||||
extensions.addRepeatedField(extension.descriptor, value);
|
||||
} else {
|
||||
extensions.setField(extension.descriptor, value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected final void mergeExtensionFields(final MessageType other) {
|
||||
((ExtendableMessage) internalGetResult()).extensions.mergeFrom(
|
||||
((ExtendableMessage) other).extensions);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
/** For use by generated code only. */
|
||||
public static <ContainingType extends MessageLite, Type>
|
||||
GeneratedExtension<ContainingType, Type>
|
||||
newGeneratedExtension() {
|
||||
return new GeneratedExtension<ContainingType, Type>();
|
||||
}
|
||||
|
||||
private static final class ExtensionDescriptor
|
||||
implements FieldSet.FieldDescriptorLite<
|
||||
ExtensionDescriptor> {
|
||||
private ExtensionDescriptor(
|
||||
final Internal.EnumLiteMap<?> enumTypeMap,
|
||||
final int number,
|
||||
final WireFormat.FieldType type,
|
||||
final boolean isRepeated,
|
||||
final boolean isPacked) {
|
||||
this.enumTypeMap = enumTypeMap;
|
||||
this.number = number;
|
||||
this.type = type;
|
||||
this.isRepeated = isRepeated;
|
||||
this.isPacked = isPacked;
|
||||
}
|
||||
|
||||
private final Internal.EnumLiteMap<?> enumTypeMap;
|
||||
private final int number;
|
||||
private final WireFormat.FieldType type;
|
||||
private final boolean isRepeated;
|
||||
private final boolean isPacked;
|
||||
|
||||
@Override
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WireFormat.FieldType getLiteType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WireFormat.JavaType getLiteJavaType() {
|
||||
return type.getJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRepeated() {
|
||||
return isRepeated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPacked() {
|
||||
return isPacked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Internal.EnumLiteMap<?> getEnumType() {
|
||||
return enumTypeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MessageLite.Builder internalMergeFrom(
|
||||
MessageLite.Builder to, MessageLite from) {
|
||||
return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExtensionDescriptor other) {
|
||||
return number - other.number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
|
||||
*
|
||||
* Users should ignore the contents of this class and only use objects of
|
||||
* this type as parameters to extension accessors and ExtensionRegistry.add().
|
||||
*/
|
||||
public static final class GeneratedExtension<
|
||||
ContainingType extends MessageLite, Type> {
|
||||
// We can't always initialize a GeneratedExtension when we first construct
|
||||
// it due to initialization order difficulties (namely, the default
|
||||
// instances may not have been constructed yet). So, we construct an
|
||||
// uninitialized GeneratedExtension once, then call internalInit() on it
|
||||
// later. Generated code will always call internalInit() on all extensions
|
||||
// as part of the static initialization code, and internalInit() throws an
|
||||
// exception if called more than once, so this method is useless to users.
|
||||
private GeneratedExtension() {}
|
||||
|
||||
private void internalInit(
|
||||
final ContainingType containingTypeDefaultInstance,
|
||||
final Type defaultValue,
|
||||
final MessageLite messageDefaultInstance,
|
||||
final ExtensionDescriptor descriptor) {
|
||||
this.containingTypeDefaultInstance = containingTypeDefaultInstance;
|
||||
this.defaultValue = defaultValue;
|
||||
this.messageDefaultInstance = messageDefaultInstance;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
/** For use by generated code only. */
|
||||
public void internalInitSingular(
|
||||
final ContainingType containingTypeDefaultInstance,
|
||||
final Type defaultValue,
|
||||
final MessageLite messageDefaultInstance,
|
||||
final Internal.EnumLiteMap<?> enumTypeMap,
|
||||
final int number,
|
||||
final WireFormat.FieldType type) {
|
||||
internalInit(
|
||||
containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
|
||||
new ExtensionDescriptor(enumTypeMap, number, type,
|
||||
false /* isRepeated */, false /* isPacked */));
|
||||
}
|
||||
|
||||
/** For use by generated code only. */
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalInitRepeated(
|
||||
final ContainingType containingTypeDefaultInstance,
|
||||
final MessageLite messageDefaultInstance,
|
||||
final Internal.EnumLiteMap<?> enumTypeMap,
|
||||
final int number,
|
||||
final WireFormat.FieldType type,
|
||||
final boolean isPacked) {
|
||||
internalInit(
|
||||
containingTypeDefaultInstance, (Type) Collections.emptyList(),
|
||||
messageDefaultInstance,
|
||||
new ExtensionDescriptor(
|
||||
enumTypeMap, number, type, true /* isRepeated */, isPacked));
|
||||
}
|
||||
|
||||
private ContainingType containingTypeDefaultInstance;
|
||||
private Type defaultValue;
|
||||
private MessageLite messageDefaultInstance;
|
||||
private ExtensionDescriptor descriptor;
|
||||
|
||||
/**
|
||||
* Default instance of the type being extended, used to identify that type.
|
||||
*/
|
||||
public ContainingType getContainingTypeDefaultInstance() {
|
||||
return containingTypeDefaultInstance;
|
||||
}
|
||||
|
||||
/** Get the field number. */
|
||||
public int getNumber() {
|
||||
return descriptor.getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the extension is an embedded message, this is the default instance of
|
||||
* that type.
|
||||
*/
|
||||
public MessageLite getMessageDefaultInstance() {
|
||||
return messageDefaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
121
OsmAnd-java/src/com/google/protobuf/Internal.java
Normal file
121
OsmAnd-java/src/com/google/protobuf/Internal.java
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* The classes contained within are used internally by the Protocol Buffer
|
||||
* library and generated message implementations. They are public only because
|
||||
* those generated messages do not reside in the {@code protobuf} package.
|
||||
* Others should not use this class directly.
|
||||
*
|
||||
* @author kenton@google.com (Kenton Varda)
|
||||
*/
|
||||
public class Internal {
|
||||
/**
|
||||
* Helper called by generated code to construct default values for string
|
||||
* fields.
|
||||
* <p>
|
||||
* The protocol compiler does not actually contain a UTF-8 decoder -- it
|
||||
* just pushes UTF-8-encoded text around without touching it. The one place
|
||||
* where this presents a problem is when generating Java string literals.
|
||||
* Unicode characters in the string literal would normally need to be encoded
|
||||
* using a Unicode escape sequence, which would require decoding them.
|
||||
* To get around this, protoc instead embeds the UTF-8 bytes into the
|
||||
* generated code and leaves it to the runtime library to decode them.
|
||||
* <p>
|
||||
* It gets worse, though. If protoc just generated a byte array, like:
|
||||
* new byte[] {0x12, 0x34, 0x56, 0x78}
|
||||
* Java actually generates *code* which allocates an array and then fills
|
||||
* in each value. This is much less efficient than just embedding the bytes
|
||||
* directly into the bytecode. To get around this, we need another
|
||||
* work-around. String literals are embedded directly, so protoc actually
|
||||
* generates a string literal corresponding to the bytes. The easiest way
|
||||
* to do this is to use the ISO-8859-1 character set, which corresponds to
|
||||
* the first 256 characters of the Unicode range. Protoc can then use
|
||||
* good old CEscape to generate the string.
|
||||
* <p>
|
||||
* So we have a string literal which represents a set of bytes which
|
||||
* represents another string. This function -- stringDefaultValue --
|
||||
* converts from the generated string to the string we actually want. The
|
||||
* generated code calls this automatically.
|
||||
*/
|
||||
public static String stringDefaultValue(String bytes) {
|
||||
try {
|
||||
return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// This should never happen since all JVMs are required to implement
|
||||
// both of the above character sets.
|
||||
throw new IllegalStateException(
|
||||
"Java VM does not support a standard character set.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper called by generated code to construct default values for bytes
|
||||
* fields.
|
||||
* <p>
|
||||
* This is a lot like {@link #stringDefaultValue}, but for bytes fields.
|
||||
* In this case we only need the second of the two hacks -- allowing us to
|
||||
* embed raw bytes as a string literal with ISO-8859-1 encoding.
|
||||
*/
|
||||
public static ByteString bytesDefaultValue(String bytes) {
|
||||
try {
|
||||
return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// This should never happen since all JVMs are required to implement
|
||||
// ISO-8859-1.
|
||||
throw new IllegalStateException(
|
||||
"Java VM does not support a standard character set.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for an enum value or value descriptor, to be used in FieldSet.
|
||||
* The lite library stores enum values directly in FieldSets but the full
|
||||
* library stores EnumValueDescriptors in order to better support reflection.
|
||||
*/
|
||||
public interface EnumLite {
|
||||
int getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for an object which maps integers to {@link EnumLite}s.
|
||||
* {@link Descriptors.EnumDescriptor} implements this interface by mapping
|
||||
* numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
|
||||
* every generated enum type has a static method internalGetValueMap() which
|
||||
* returns an implementation of this type that maps numbers to enum values.
|
||||
*/
|
||||
public interface EnumLiteMap<T extends EnumLite> {
|
||||
T findValueByNumber(int number);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Thrown when a protocol message being parsed is invalid in some way,
|
||||
* e.g. it contains a malformed varint or a negative byte length.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public class InvalidProtocolBufferException extends IOException {
|
||||
private static final long serialVersionUID = -1616151763072450476L;
|
||||
|
||||
public InvalidProtocolBufferException(final String description) {
|
||||
super(description);
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException truncatedMessage() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"While parsing a protocol message, the input ended unexpectedly " +
|
||||
"in the middle of a field. This could mean either than the " +
|
||||
"input has been truncated or that an embedded message " +
|
||||
"misreported its own length.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException negativeSize() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"CodedInputStream encountered an embedded string or message " +
|
||||
"which claimed to have negative size.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException malformedVarint() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"CodedInputStream encountered a malformed varint.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidTag() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message contained an invalid tag (zero).");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidEndTag() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message end-group tag did not match expected tag.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException invalidWireType() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message tag had invalid wire type.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException recursionLimitExceeded() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message had too many levels of nesting. May be malicious. " +
|
||||
"Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
|
||||
}
|
||||
|
||||
static InvalidProtocolBufferException sizeLimitExceeded() {
|
||||
return new InvalidProtocolBufferException(
|
||||
"Protocol message was too large. May be malicious. " +
|
||||
"Use CodedInputStream.setSizeLimit() to increase the size limit.");
|
||||
}
|
||||
}
|
325
OsmAnd-java/src/com/google/protobuf/Message.java
Normal file
325
OsmAnd-java/src/com/google/protobuf/Message.java
Normal file
|
@ -0,0 +1,325 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
|
||||
// mergeFrom*() could return BuilderType for better type-safety.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message objects.
|
||||
* <p>
|
||||
* See also {@link MessageLite}, which defines most of the methods that typical
|
||||
* users care about. {@link Message} adds to it methods that are not available
|
||||
* in the "lite" runtime. The biggest added features are introspection and
|
||||
* reflection -- i.e., getting descriptors for the message type and accessing
|
||||
* the field values dynamically.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface Message extends MessageLite {
|
||||
/**
|
||||
* Get the message's type's descriptor. This differs from the
|
||||
* {@code getDescriptor()} method of generated message classes in that
|
||||
* this method is an abstract method of the {@code Message} interface
|
||||
* whereas {@code getDescriptor()} is a static method of a specific class.
|
||||
* They return the same thing.
|
||||
*/
|
||||
Descriptors.Descriptor getDescriptorForType();
|
||||
|
||||
// (From MessageLite, re-declared here only for return type covariance.)
|
||||
@Override
|
||||
Message getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* Returns a collection of all the fields in this message which are set
|
||||
* and their corresponding values. A singular ("required" or "optional")
|
||||
* field is set iff hasField() returns true for that field. A "repeated"
|
||||
* field is set iff getRepeatedFieldSize() is greater than zero. The
|
||||
* values are exactly what would be returned by calling
|
||||
* {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
|
||||
* is guaranteed to be a sorted map, so iterating over it will return fields
|
||||
* in order by field number.
|
||||
*/
|
||||
Map<Descriptors.FieldDescriptor, Object> getAllFields();
|
||||
|
||||
/**
|
||||
* Returns true if the given field is set. This is exactly equivalent to
|
||||
* calling the generated "has" accessor method corresponding to the field.
|
||||
* @throws IllegalArgumentException The field is a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
boolean hasField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Obtains the value of the given field, or the default value if it is
|
||||
* not set. For primitive fields, the boxed primitive value is returned.
|
||||
* For enum fields, the EnumValueDescriptor for the value is returend. For
|
||||
* embedded message fields, the sub-message is returned. For repeated
|
||||
* fields, a java.util.List is returned.
|
||||
*/
|
||||
Object getField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Gets the number of elements of a repeated field. This is exactly
|
||||
* equivalent to calling the generated "Count" accessor method corresponding
|
||||
* to the field.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Gets an element of a repeated field. For primitive fields, the boxed
|
||||
* primitive value is returned. For enum fields, the EnumValueDescriptor
|
||||
* for the value is returend. For embedded message fields, the sub-message
|
||||
* is returned.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
|
||||
|
||||
/** Get the {@link UnknownFieldSet} for this message. */
|
||||
UnknownFieldSet getUnknownFields();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Comparison and hashing
|
||||
|
||||
/**
|
||||
* Compares the specified object with this message for equality. Returns
|
||||
* <tt>true</tt> if the given object is a message of the same type (as
|
||||
* defined by {@code getDescriptorForType()}) and has identical values for
|
||||
* all of its fields.
|
||||
*
|
||||
* @param other object to be compared for equality with this message
|
||||
* @return <tt>true</tt> if the specified object is equal to this message
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object other);
|
||||
|
||||
/**
|
||||
* Returns the hash code value for this message. The hash code of a message
|
||||
* is defined to be <tt>getDescriptor().hashCode() ^ map.hashCode()</tt>,
|
||||
* where <tt>map</tt> is a map of field numbers to field values.
|
||||
*
|
||||
* @return the hash code value for this message
|
||||
* @see Map#hashCode()
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Converts the message to a string in protocol buffer text format. This is
|
||||
* just a trivial wrapper around {@link TextFormat#printToString(Message)}.
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
// =================================================================
|
||||
// Builders
|
||||
|
||||
// (From MessageLite, re-declared here only for return type covariance.)
|
||||
@Override
|
||||
Builder newBuilderForType();
|
||||
@Override
|
||||
Builder toBuilder();
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message builders.
|
||||
*/
|
||||
interface Builder extends MessageLite.Builder {
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
Builder clear();
|
||||
|
||||
/**
|
||||
* Merge {@code other} into the message being built. {@code other} must
|
||||
* have the exact same type as {@code this} (i.e.
|
||||
* {@code getDescriptorForType() == other.getDescriptorForType()}).
|
||||
*
|
||||
* Merging occurs as follows. For each field:<br>
|
||||
* * For singular primitive fields, if the field is set in {@code other},
|
||||
* then {@code other}'s value overwrites the value in this message.<br>
|
||||
* * For singular message fields, if the field is set in {@code other},
|
||||
* it is merged into the corresponding sub-message of this message
|
||||
* using the same merging rules.<br>
|
||||
* * For repeated fields, the elements in {@code other} are concatenated
|
||||
* with the elements in this message.
|
||||
*
|
||||
* This is equivalent to the {@code Message::MergeFrom} method in C++.
|
||||
*/
|
||||
Builder mergeFrom(Message other);
|
||||
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
Message build();
|
||||
@Override
|
||||
Message buildPartial();
|
||||
@Override
|
||||
Builder clone();
|
||||
@Override
|
||||
Builder mergeFrom(CodedInputStream input) throws IOException;
|
||||
@Override
|
||||
Builder mergeFrom(CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Get the message's type's descriptor.
|
||||
* See {@link Message#getDescriptorForType()}.
|
||||
*/
|
||||
Descriptors.Descriptor getDescriptorForType();
|
||||
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
Message getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* Like {@link Message#getAllFields()}. The returned map may or may not
|
||||
* reflect future changes to the builder. Either way, the returned map is
|
||||
* itself unmodifiable.
|
||||
*/
|
||||
Map<Descriptors.FieldDescriptor, Object> getAllFields();
|
||||
|
||||
/**
|
||||
* Create a Builder for messages of the appropriate type for the given
|
||||
* field. Messages built with this can then be passed to setField(),
|
||||
* setRepeatedField(), or addRepeatedField().
|
||||
*/
|
||||
Builder newBuilderForField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/** Like {@link Message#hasField(Descriptors.FieldDescriptor)} */
|
||||
boolean hasField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/** Like {@link Message#getField(Descriptors.FieldDescriptor)} */
|
||||
Object getField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Sets a field to the given value. The value must be of the correct type
|
||||
* for this field, i.e. the same type that
|
||||
* {@link Message#getField(Descriptors.FieldDescriptor)} would return.
|
||||
*/
|
||||
Builder setField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/**
|
||||
* Clears the field. This is exactly equivalent to calling the generated
|
||||
* "clear" accessor method corresponding to the field.
|
||||
*/
|
||||
Builder clearField(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Like {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}
|
||||
*/
|
||||
int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
|
||||
|
||||
/**
|
||||
* Like {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}
|
||||
*/
|
||||
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
|
||||
|
||||
/**
|
||||
* Sets an element of a repeated field to the given value. The value must
|
||||
* be of the correct type for this field, i.e. the same type that
|
||||
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
|
||||
* return.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
Builder setRepeatedField(Descriptors.FieldDescriptor field,
|
||||
int index, Object value);
|
||||
|
||||
/**
|
||||
* Like {@code setRepeatedField}, but appends the value as a new element.
|
||||
* @throws IllegalArgumentException The field is not a repeated field, or
|
||||
* {@code field.getContainingType() != getDescriptorForType()}.
|
||||
*/
|
||||
Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
|
||||
|
||||
/** Get the {@link UnknownFieldSet} for this message. */
|
||||
UnknownFieldSet getUnknownFields();
|
||||
|
||||
/** Set the {@link UnknownFieldSet} for this message. */
|
||||
Builder setUnknownFields(UnknownFieldSet unknownFields);
|
||||
|
||||
/**
|
||||
* Merge some unknown fields into the {@link UnknownFieldSet} for this
|
||||
* message.
|
||||
*/
|
||||
Builder mergeUnknownFields(UnknownFieldSet unknownFields);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
// (From MessageLite.Builder, re-declared here only for return type
|
||||
// covariance.)
|
||||
@Override
|
||||
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
@Override
|
||||
Builder mergeFrom(ByteString data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
@Override
|
||||
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
@Override
|
||||
Builder mergeFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException;
|
||||
@Override
|
||||
Builder mergeFrom(byte[] data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
@Override
|
||||
Builder mergeFrom(byte[] data, int off, int len,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
@Override
|
||||
Builder mergeFrom(InputStream input) throws IOException;
|
||||
@Override
|
||||
Builder mergeFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
@Override
|
||||
boolean mergeDelimitedFrom(InputStream input)
|
||||
throws IOException;
|
||||
@Override
|
||||
boolean mergeDelimitedFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
}
|
||||
}
|
335
OsmAnd-java/src/com/google/protobuf/MessageLite.java
Normal file
335
OsmAnd-java/src/com/google/protobuf/MessageLite.java
Normal file
|
@ -0,0 +1,335 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
|
||||
// mergeFrom*() could return BuilderType for better type-safety.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message objects.
|
||||
*
|
||||
* <p>This interface is implemented by all protocol message objects. Non-lite
|
||||
* messages additionally implement the Message interface, which is a subclass
|
||||
* of MessageLite. Use MessageLite instead when you only need the subset of
|
||||
* features which it supports -- namely, nothing that uses descriptors or
|
||||
* reflection. You can instruct the protocol compiler to generate classes
|
||||
* which implement only MessageLite, not the full Message interface, by adding
|
||||
* the follow line to the .proto file:
|
||||
* <pre>
|
||||
* option optimize_for = LITE_RUNTIME;
|
||||
* </pre>
|
||||
*
|
||||
* <p>This is particularly useful on resource-constrained systems where the
|
||||
* full protocol buffers runtime library is too big.
|
||||
*
|
||||
* <p>Note that on non-constrained systems (e.g. servers) when you need to link
|
||||
* in lots of protocol definitions, a better way to reduce total code footprint
|
||||
* is to use {@code optimize_for = CODE_SIZE}. This will make the generated
|
||||
* code smaller while still supporting all the same features (at the expense of
|
||||
* speed). {@code optimize_for = LITE_RUNTIME} is best when you only have a
|
||||
* small number of message types linked into your binary, in which case the
|
||||
* size of the protocol buffers runtime itself is the biggest problem.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface MessageLite {
|
||||
/**
|
||||
* Get an instance of the type with all fields set to their default values.
|
||||
* This may or may not be a singleton. This differs from the
|
||||
* {@code getDefaultInstance()} method of generated message classes in that
|
||||
* this method is an abstract method of the {@code MessageLite} interface
|
||||
* whereas {@code getDefaultInstance()} is a static method of a specific
|
||||
* class. They return the same thing.
|
||||
*/
|
||||
MessageLite getDefaultInstanceForType();
|
||||
|
||||
/**
|
||||
* Returns true if all required fields in the message and all embedded
|
||||
* messages are set, false otherwise.
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Serializes the message and writes it to {@code output}. This does not
|
||||
* flush or close the stream.
|
||||
*/
|
||||
void writeTo(CodedOutputStream output) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the number of bytes required to encode this message. The result
|
||||
* is only computed on the first call and memoized after that.
|
||||
*/
|
||||
int getSerializedSize();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code ByteString} and returns it. This is
|
||||
* just a trivial wrapper around
|
||||
* {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
ByteString toByteString();
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code byte} array and returns it. This is
|
||||
* just a trivial wrapper around
|
||||
* {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
byte[] toByteArray();
|
||||
|
||||
/**
|
||||
* Serializes the message and writes it to {@code output}. This is just a
|
||||
* trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
|
||||
* not flush or close the stream.
|
||||
* <p>
|
||||
* NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
|
||||
* any more data to the stream after the message, you must somehow ensure
|
||||
* that the parser on the receiving end does not interpret this as being
|
||||
* part of the protocol message. This can be done e.g. by writing the size
|
||||
* of the message before the data, then making sure to limit the input to
|
||||
* that size on the receiving end (e.g. by wrapping the InputStream in one
|
||||
* which limits the input). Alternatively, just use
|
||||
* {@link #writeDelimitedTo(OutputStream)}.
|
||||
*/
|
||||
void writeTo(OutputStream output) throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link #writeTo(OutputStream)}, but writes the size of the message
|
||||
* as a varint before writing the data. This allows more data to be written
|
||||
* to the stream after the message without the need to delimit the message
|
||||
* data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
|
||||
* the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
|
||||
* to parse messages written by this method.
|
||||
*/
|
||||
void writeDelimitedTo(OutputStream output) throws IOException;
|
||||
|
||||
// =================================================================
|
||||
// Builders
|
||||
|
||||
/**
|
||||
* Constructs a new builder for a message of the same type as this message.
|
||||
*/
|
||||
Builder newBuilderForType();
|
||||
|
||||
/**
|
||||
* Constructs a builder initialized with the current message. Use this to
|
||||
* derive a new message from the current one.
|
||||
*/
|
||||
Builder toBuilder();
|
||||
|
||||
/**
|
||||
* Abstract interface implemented by Protocol Message builders.
|
||||
*/
|
||||
interface Builder extends Cloneable {
|
||||
/** Resets all fields to their default values. */
|
||||
Builder clear();
|
||||
|
||||
/**
|
||||
* Construct the final message. Once this is called, the Builder is no
|
||||
* longer valid, and calling any other method will result in undefined
|
||||
* behavior and may throw a NullPointerException. If you need to continue
|
||||
* working with the builder after calling {@code build()}, {@code clone()}
|
||||
* it first.
|
||||
* @throws UninitializedMessageException The message is missing one or more
|
||||
* required fields (i.e. {@link #isInitialized()} returns false).
|
||||
* Use {@link #buildPartial()} to bypass this check.
|
||||
*/
|
||||
MessageLite build();
|
||||
|
||||
/**
|
||||
* Like {@link #build()}, but does not throw an exception if the message
|
||||
* is missing required fields. Instead, a partial message is returned.
|
||||
* Once this is called, the Builder is no longer valid, and calling any
|
||||
* will result in undefined behavior and may throw a NullPointerException.
|
||||
*
|
||||
* If you need to continue working with the builder after calling
|
||||
* {@code buildPartial()}, {@code clone()} it first.
|
||||
*/
|
||||
MessageLite buildPartial();
|
||||
|
||||
/**
|
||||
* Clones the Builder.
|
||||
* @see Object#clone()
|
||||
*/
|
||||
Builder clone();
|
||||
|
||||
/**
|
||||
* Returns true if all required fields in the message and all embedded
|
||||
* messages are set, false otherwise.
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Parses a message of this type from the input and merges it with this
|
||||
* message, as if using {@link Builder#mergeFrom(MessageLite)}.
|
||||
*
|
||||
* <p>Warning: This does not verify that all required fields are present in
|
||||
* the input message. If you call {@link #build()} without setting all
|
||||
* required fields, it will throw an {@link UninitializedMessageException},
|
||||
* which is a {@code RuntimeException} and thus might not be caught. There
|
||||
* are a few good ways to deal with this:
|
||||
* <ul>
|
||||
* <li>Call {@link #isInitialized()} to verify that all required fields
|
||||
* are set before building.
|
||||
* <li>Parse the message separately using one of the static
|
||||
* {@code parseFrom} methods, then use {@link #mergeFrom(MessageLite)}
|
||||
* to merge it with this one. {@code parseFrom} will throw an
|
||||
* {@link InvalidProtocolBufferException} (an {@code IOException})
|
||||
* if some required fields are missing.
|
||||
* <li>Use {@code buildPartial()} to build, which ignores missing
|
||||
* required fields.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: The caller should call
|
||||
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
|
||||
* verify that the last tag seen was the appropriate end-group tag,
|
||||
* or zero for EOF.
|
||||
*/
|
||||
Builder mergeFrom(CodedInputStream input) throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
|
||||
* parses extensions. The extensions that you want to be able to parse
|
||||
* must be registered in {@code extensionRegistry}. Extensions not in
|
||||
* the registry will be treated as unknown fields.
|
||||
*/
|
||||
Builder mergeFrom(CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Get the message's type's default instance.
|
||||
* See {@link MessageLite#getDefaultInstanceForType()}.
|
||||
*/
|
||||
MessageLite getDefaultInstanceForType();
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
|
||||
*/
|
||||
Builder mergeFrom(ByteString data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
Builder mergeFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
|
||||
*/
|
||||
Builder mergeFrom(byte[] data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse {@code data} as a message of this type and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
|
||||
*/
|
||||
Builder mergeFrom(byte[] data, int off, int len,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parse a message of this type from {@code input} and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
|
||||
* reads the <i>entire</i> input (unless it throws an exception). If you
|
||||
* want it to stop earlier, you will need to wrap your input in some
|
||||
* wrapper stream that limits reading. Or, use
|
||||
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
|
||||
* and {@link #mergeDelimitedFrom(InputStream)} to read it.
|
||||
* <p>
|
||||
* Despite usually reading the entire input, this does not close the stream.
|
||||
*/
|
||||
Builder mergeFrom(InputStream input) throws IOException;
|
||||
|
||||
/**
|
||||
* Parse a message of this type from {@code input} and merge it with the
|
||||
* message being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
|
||||
*/
|
||||
Builder mergeFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
|
||||
* Instead, the size of the message (encoded as a varint) is read first,
|
||||
* then the message data. Use
|
||||
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
|
||||
* this format.
|
||||
*
|
||||
* @returns True if successful, or false if the stream is at EOF when the
|
||||
* method starts. Any other error (including reaching EOF during
|
||||
* parsing) will cause an exception to be thrown.
|
||||
*/
|
||||
boolean mergeDelimitedFrom(InputStream input)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
|
||||
*/
|
||||
boolean mergeDelimitedFrom(InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws IOException;
|
||||
}
|
||||
}
|
59
OsmAnd-java/src/com/google/protobuf/ProtocolMessageEnum.java
Normal file
59
OsmAnd-java/src/com/google/protobuf/ProtocolMessageEnum.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
|
||||
/**
|
||||
* Interface of useful methods added to all enums generated by the protocol
|
||||
* compiler.
|
||||
*/
|
||||
public interface ProtocolMessageEnum extends Internal.EnumLite {
|
||||
|
||||
/**
|
||||
* Return the value's numeric value as defined in the .proto file.
|
||||
*/
|
||||
@Override
|
||||
int getNumber();
|
||||
|
||||
/**
|
||||
* Return the value's descriptor, which contains information such as
|
||||
* value name, number, and type.
|
||||
*/
|
||||
EnumValueDescriptor getValueDescriptor();
|
||||
|
||||
/**
|
||||
* Return the enum type's descriptor, which contains information
|
||||
* about each defined value, etc.
|
||||
*/
|
||||
EnumDescriptor getDescriptorForType();
|
||||
}
|
47
OsmAnd-java/src/com/google/protobuf/RpcCallback.java
Normal file
47
OsmAnd-java/src/com/google/protobuf/RpcCallback.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Interface for an RPC callback, normally called when an RPC completes.
|
||||
* {@code ParameterType} is normally the method's response message type.
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface RpcCallback<ParameterType> {
|
||||
void run(ParameterType parameter);
|
||||
}
|
71
OsmAnd-java/src/com/google/protobuf/RpcChannel.java
Normal file
71
OsmAnd-java/src/com/google/protobuf/RpcChannel.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* <p>Abstract interface for an RPC channel. An {@code RpcChannel} represents a
|
||||
* communication line to a {@link Service} which can be used to call that
|
||||
* {@link Service}'s methods. The {@link Service} may be running on another
|
||||
* machine. Normally, you should not call an {@code RpcChannel} directly, but
|
||||
* instead construct a stub {@link Service} wrapping it. Example:
|
||||
*
|
||||
* <pre>
|
||||
* RpcChannel channel = rpcImpl.newChannel("remotehost.example.com:1234");
|
||||
* RpcController controller = rpcImpl.newController();
|
||||
* MyService service = MyService.newStub(channel);
|
||||
* service.myMethod(controller, request, callback);
|
||||
* </pre>
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface RpcChannel {
|
||||
/**
|
||||
* Call the given method of the remote service. This method is similar to
|
||||
* {@code Service.callMethod()} with one important difference: the caller
|
||||
* decides the types of the {@code Message} objects, not the callee. The
|
||||
* request may be of any type as long as
|
||||
* {@code request.getDescriptor() == method.getInputType()}.
|
||||
* The response passed to the callback will be of the same type as
|
||||
* {@code responsePrototype} (which must have
|
||||
* {@code getDescriptor() == method.getOutputType()}).
|
||||
*/
|
||||
void callMethod(Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
Message responsePrototype,
|
||||
RpcCallback<Message> done);
|
||||
}
|
118
OsmAnd-java/src/com/google/protobuf/RpcController.java
Normal file
118
OsmAnd-java/src/com/google/protobuf/RpcController.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* <p>An {@code RpcController} mediates a single method call. The primary
|
||||
* purpose of the controller is to provide a way to manipulate settings
|
||||
* specific to the RPC implementation and to find out about RPC-level errors.
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
*
|
||||
* <p>The methods provided by the {@code RpcController} interface are intended
|
||||
* to be a "least common denominator" set of features which we expect all
|
||||
* implementations to support. Specific implementations may provide more
|
||||
* advanced features (e.g. deadline propagation).
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface RpcController {
|
||||
// -----------------------------------------------------------------
|
||||
// These calls may be made from the client side only. Their results
|
||||
// are undefined on the server side (may throw RuntimeExceptions).
|
||||
|
||||
/**
|
||||
* Resets the RpcController to its initial state so that it may be reused in
|
||||
* a new call. This can be called from the client side only. It must not
|
||||
* be called while an RPC is in progress.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* After a call has finished, returns true if the call failed. The possible
|
||||
* reasons for failure depend on the RPC implementation. {@code failed()}
|
||||
* most only be called on the client side, and must not be called before a
|
||||
* call has finished.
|
||||
*/
|
||||
boolean failed();
|
||||
|
||||
/**
|
||||
* If {@code failed()} is {@code true}, returns a human-readable description
|
||||
* of the error.
|
||||
*/
|
||||
String errorText();
|
||||
|
||||
/**
|
||||
* Advises the RPC system that the caller desires that the RPC call be
|
||||
* canceled. The RPC system may cancel it immediately, may wait awhile and
|
||||
* then cancel it, or may not even cancel the call at all. If the call is
|
||||
* canceled, the "done" callback will still be called and the RpcController
|
||||
* will indicate that the call failed at that time.
|
||||
*/
|
||||
void startCancel();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// These calls may be made from the server side only. Their results
|
||||
// are undefined on the client side (may throw RuntimeExceptions).
|
||||
|
||||
/**
|
||||
* Causes {@code failed()} to return true on the client side. {@code reason}
|
||||
* will be incorporated into the message returned by {@code errorText()}.
|
||||
* If you find you need to return machine-readable information about
|
||||
* failures, you should incorporate it into your response protocol buffer
|
||||
* and should NOT call {@code setFailed()}.
|
||||
*/
|
||||
void setFailed(String reason);
|
||||
|
||||
/**
|
||||
* If {@code true}, indicates that the client canceled the RPC, so the server
|
||||
* may as well give up on replying to it. This method must be called on the
|
||||
* server side only. The server should still call the final "done" callback.
|
||||
*/
|
||||
boolean isCanceled();
|
||||
|
||||
/**
|
||||
* Asks that the given callback be called when the RPC is canceled. The
|
||||
* parameter passed to the callback will always be {@code null}. The
|
||||
* callback will always be called exactly once. If the RPC completes without
|
||||
* being canceled, the callback will be called after completion. If the RPC
|
||||
* has already been canceled when NotifyOnCancel() is called, the callback
|
||||
* will be called immediately.
|
||||
*
|
||||
* <p>{@code notifyOnCancel()} must be called no more than once per request.
|
||||
* It must be called on the server side only.
|
||||
*/
|
||||
void notifyOnCancel(RpcCallback<Object> callback);
|
||||
}
|
137
OsmAnd-java/src/com/google/protobuf/RpcUtil.java
Normal file
137
OsmAnd-java/src/com/google/protobuf/RpcUtil.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Grab-bag of utility functions useful when dealing with RPCs.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class RpcUtil {
|
||||
private RpcUtil() {}
|
||||
|
||||
/**
|
||||
* Take an {@code RpcCallback<Message>} and convert it to an
|
||||
* {@code RpcCallback} accepting a specific message type. This is always
|
||||
* type-safe (parameter type contravariance).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <Type extends Message> RpcCallback<Type>
|
||||
specializeCallback(final RpcCallback<Message> originalCallback) {
|
||||
return (RpcCallback<Type>)originalCallback;
|
||||
// The above cast works, but only due to technical details of the Java
|
||||
// implementation. A more theoretically correct -- but less efficient --
|
||||
// implementation would be as follows:
|
||||
// return new RpcCallback<Type>() {
|
||||
// public void run(Type parameter) {
|
||||
// originalCallback.run(parameter);
|
||||
// }
|
||||
// };
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an {@code RpcCallback} accepting a specific message type and convert
|
||||
* it to an {@code RpcCallback<Message>}. The generalized callback will
|
||||
* accept any message object which has the same descriptor, and will convert
|
||||
* it to the correct class before calling the original callback. However,
|
||||
* if the generalized callback is given a message with a different descriptor,
|
||||
* an exception will be thrown.
|
||||
*/
|
||||
public static <Type extends Message>
|
||||
RpcCallback<Message> generalizeCallback(
|
||||
final RpcCallback<Type> originalCallback,
|
||||
final Class<Type> originalClass,
|
||||
final Type defaultInstance) {
|
||||
return new RpcCallback<Message>() {
|
||||
@Override
|
||||
public void run(final Message parameter) {
|
||||
Type typedParameter;
|
||||
try {
|
||||
typedParameter = originalClass.cast(parameter);
|
||||
} catch (ClassCastException ignored) {
|
||||
typedParameter = copyAsType(defaultInstance, parameter);
|
||||
}
|
||||
originalCallback.run(typedParameter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new message of type "Type" which is a copy of "source". "source"
|
||||
* must have the same descriptor but may be a different class (e.g.
|
||||
* DynamicMessage).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <Type extends Message> Type copyAsType(
|
||||
final Type typeDefaultInstance, final Message source) {
|
||||
return (Type)typeDefaultInstance.newBuilderForType()
|
||||
.mergeFrom(source)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a callback which can only be called once. This may be useful for
|
||||
* security, when passing a callback to untrusted code: most callbacks do
|
||||
* not expect to be called more than once, so doing so may expose bugs if it
|
||||
* is not prevented.
|
||||
*/
|
||||
public static <ParameterType>
|
||||
RpcCallback<ParameterType> newOneTimeCallback(
|
||||
final RpcCallback<ParameterType> originalCallback) {
|
||||
return new RpcCallback<ParameterType>() {
|
||||
private boolean alreadyCalled = false;
|
||||
|
||||
@Override
|
||||
public void run(final ParameterType parameter) {
|
||||
synchronized(this) {
|
||||
if (alreadyCalled) {
|
||||
throw new AlreadyCalledException();
|
||||
}
|
||||
alreadyCalled = true;
|
||||
}
|
||||
|
||||
originalCallback.run(parameter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when a one-time callback is called more than once.
|
||||
*/
|
||||
public static final class AlreadyCalledException extends RuntimeException {
|
||||
private static final long serialVersionUID = 5469741279507848266L;
|
||||
|
||||
public AlreadyCalledException() {
|
||||
super("This RpcCallback was already called and cannot be called " +
|
||||
"multiple times.");
|
||||
}
|
||||
}
|
||||
}
|
117
OsmAnd-java/src/com/google/protobuf/Service.java
Normal file
117
OsmAnd-java/src/com/google/protobuf/Service.java
Normal file
|
@ -0,0 +1,117 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Abstract base interface for protocol-buffer-based RPC services. Services
|
||||
* themselves are abstract classes (implemented either by servers or as
|
||||
* stubs), but they subclass this base interface. The methods of this
|
||||
* interface can be used to call the methods of the service without knowing
|
||||
* its exact type at compile time (analogous to the Message interface).
|
||||
*
|
||||
* <p>Starting with version 2.3.0, RPC implementations should not try to build
|
||||
* on this, but should instead provide code generator plugins which generate
|
||||
* code specific to the particular RPC implementation. This way the generated
|
||||
* code can be more appropriate for the implementation in use and can avoid
|
||||
* unnecessary layers of indirection.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public interface Service {
|
||||
/**
|
||||
* Get the {@code ServiceDescriptor} describing this service and its methods.
|
||||
*/
|
||||
Descriptors.ServiceDescriptor getDescriptorForType();
|
||||
|
||||
/**
|
||||
* <p>Call a method of the service specified by MethodDescriptor. This is
|
||||
* normally implemented as a simple {@code switch()} that calls the standard
|
||||
* definitions of the service's methods.
|
||||
*
|
||||
* <p>Preconditions:
|
||||
* <ul>
|
||||
* <li>{@code method.getService() == getDescriptorForType()}
|
||||
* <li>{@code request} is of the exact same class as the object returned by
|
||||
* {@code getRequestPrototype(method)}.
|
||||
* <li>{@code controller} is of the correct type for the RPC implementation
|
||||
* being used by this Service. For stubs, the "correct type" depends
|
||||
* on the RpcChannel which the stub is using. Server-side Service
|
||||
* implementations are expected to accept whatever type of
|
||||
* {@code RpcController} the server-side RPC implementation uses.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Postconditions:
|
||||
* <ul>
|
||||
* <li>{@code done} will be called when the method is complete. This may be
|
||||
* before {@code callMethod()} returns or it may be at some point in
|
||||
* the future.
|
||||
* <li>The parameter to {@code done} is the response. It must be of the
|
||||
* exact same type as would be returned by
|
||||
* {@code getResponsePrototype(method)}.
|
||||
* <li>If the RPC failed, the parameter to {@code done} will be
|
||||
* {@code null}. Further details about the failure can be found by
|
||||
* querying {@code controller}.
|
||||
* </ul>
|
||||
*/
|
||||
void callMethod(Descriptors.MethodDescriptor method,
|
||||
RpcController controller,
|
||||
Message request,
|
||||
RpcCallback<Message> done);
|
||||
|
||||
/**
|
||||
* <p>{@code callMethod()} requires that the request passed in is of a
|
||||
* particular subclass of {@code Message}. {@code getRequestPrototype()}
|
||||
* gets the default instances of this type for a given method. You can then
|
||||
* call {@code Message.newBuilderForType()} on this instance to
|
||||
* construct a builder to build an object which you can then pass to
|
||||
* {@code callMethod()}.
|
||||
*
|
||||
* <p>Example:
|
||||
* <pre>
|
||||
* MethodDescriptor method =
|
||||
* service.getDescriptorForType().findMethodByName("Foo");
|
||||
* Message request =
|
||||
* stub.getRequestPrototype(method).newBuilderForType()
|
||||
* .mergeFrom(input).build();
|
||||
* service.callMethod(method, request, callback);
|
||||
* </pre>
|
||||
*/
|
||||
Message getRequestPrototype(Descriptors.MethodDescriptor method);
|
||||
|
||||
/**
|
||||
* Like {@code getRequestPrototype()}, but gets a prototype of the response
|
||||
* message. {@code getResponsePrototype()} is generally not needed because
|
||||
* the {@code Service} implementation constructs the response message itself,
|
||||
* but it may be useful in some cases to know ahead of time what type of
|
||||
* object will be returned.
|
||||
*/
|
||||
Message getResponsePrototype(Descriptors.MethodDescriptor method);
|
||||
}
|
44
OsmAnd-java/src/com/google/protobuf/ServiceException.java
Normal file
44
OsmAnd-java/src/com/google/protobuf/ServiceException.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* Thrown by blocking RPC methods when a failure occurs.
|
||||
*
|
||||
* @author cpovirk@google.com (Chris Povirk)
|
||||
*/
|
||||
public final class ServiceException extends Exception {
|
||||
private static final long serialVersionUID = -1219262335729891920L;
|
||||
|
||||
public ServiceException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
1352
OsmAnd-java/src/com/google/protobuf/TextFormat.java
Normal file
1352
OsmAnd-java/src/com/google/protobuf/TextFormat.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,99 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Thrown when attempting to build a protocol message that is missing required
|
||||
* fields. This is a {@code RuntimeException} because it normally represents
|
||||
* a programming error: it happens when some code which constructs a message
|
||||
* fails to set all the fields. {@code parseFrom()} methods <b>do not</b>
|
||||
* throw this; they throw an {@link InvalidProtocolBufferException} if
|
||||
* required fields are missing, because it is not a programming error to
|
||||
* receive an incomplete message. In other words,
|
||||
* {@code UninitializedMessageException} should never be thrown by correct
|
||||
* code, but {@code InvalidProtocolBufferException} might be.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public class UninitializedMessageException extends RuntimeException {
|
||||
private static final long serialVersionUID = -7466929953374883507L;
|
||||
|
||||
public UninitializedMessageException(final MessageLite message) {
|
||||
super("Message was missing required fields. (Lite runtime could not " +
|
||||
"determine which fields were missing).");
|
||||
missingFields = null;
|
||||
}
|
||||
|
||||
public UninitializedMessageException(final List<String> missingFields) {
|
||||
super(buildDescription(missingFields));
|
||||
this.missingFields = missingFields;
|
||||
}
|
||||
|
||||
private final List<String> missingFields;
|
||||
|
||||
/**
|
||||
* Get a list of human-readable names of required fields missing from this
|
||||
* message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
|
||||
* Returns null if the lite runtime was used, since it lacks the ability to
|
||||
* find missing fields.
|
||||
*/
|
||||
public List<String> getMissingFields() {
|
||||
return Collections.unmodifiableList(missingFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this exception to an {@link InvalidProtocolBufferException}.
|
||||
* When a parsed message is missing required fields, this should be thrown
|
||||
* instead of {@code UninitializedMessageException}.
|
||||
*/
|
||||
public InvalidProtocolBufferException asInvalidProtocolBufferException() {
|
||||
return new InvalidProtocolBufferException(getMessage());
|
||||
}
|
||||
|
||||
/** Construct the description string for this exception. */
|
||||
private static String buildDescription(final List<String> missingFields) {
|
||||
final StringBuilder description =
|
||||
new StringBuilder("Message missing required fields: ");
|
||||
boolean first = true;
|
||||
for (final String field : missingFields) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
description.append(", ");
|
||||
}
|
||||
description.append(field);
|
||||
}
|
||||
return description.toString();
|
||||
}
|
||||
}
|
980
OsmAnd-java/src/com/google/protobuf/UnknownFieldSet.java
Normal file
980
OsmAnd-java/src/com/google/protobuf/UnknownFieldSet.java
Normal file
|
@ -0,0 +1,980 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
|
||||
|
||||
/**
|
||||
* {@code UnknownFieldSet} is used to keep track of fields which were seen when
|
||||
* parsing a protocol message but whose field numbers or types are unrecognized.
|
||||
* This most frequently occurs when new fields are added to a message type
|
||||
* and then messages containing those feilds are read by old software that was
|
||||
* compiled before the new types were added.
|
||||
*
|
||||
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
|
||||
* {@link Message.Builder} contains an {@link Builder}).
|
||||
*
|
||||
* <p>Most users will never need to use this class.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class UnknownFieldSet implements MessageLite {
|
||||
private UnknownFieldSet() {}
|
||||
|
||||
/** Create a new {@link Builder}. */
|
||||
public static Builder newBuilder() {
|
||||
return Builder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Builder} and initialize it to be a copy
|
||||
* of {@code copyFrom}.
|
||||
*/
|
||||
public static Builder newBuilder(final UnknownFieldSet copyFrom) {
|
||||
return newBuilder().mergeFrom(copyFrom);
|
||||
}
|
||||
|
||||
/** Get an empty {@code UnknownFieldSet}. */
|
||||
public static UnknownFieldSet getDefaultInstance() {
|
||||
return defaultInstance;
|
||||
}
|
||||
@Override
|
||||
public UnknownFieldSet getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
private static final UnknownFieldSet defaultInstance =
|
||||
new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
|
||||
|
||||
/**
|
||||
* Construct an {@code UnknownFieldSet} around the given map. The map is
|
||||
* expected to be immutable.
|
||||
*/
|
||||
private UnknownFieldSet(final Map<Integer, Field> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
private Map<Integer, Field> fields;
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
return (other instanceof UnknownFieldSet) &&
|
||||
fields.equals(((UnknownFieldSet) other).fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return fields.hashCode();
|
||||
}
|
||||
|
||||
/** Get a map of fields in the set by number. */
|
||||
public Map<Integer, Field> asMap() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/** Check if the given field number is present in the set. */
|
||||
public boolean hasField(final int number) {
|
||||
return fields.containsKey(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field by number. Returns an empty field if not present. Never
|
||||
* returns {@code null}.
|
||||
*/
|
||||
public Field getField(final int number) {
|
||||
final Field result = fields.get(number);
|
||||
return (result == null) ? Field.getDefaultInstance() : result;
|
||||
}
|
||||
|
||||
/** Serializes the set and writes it to {@code output}. */
|
||||
@Override
|
||||
public void writeTo(final CodedOutputStream output) throws IOException {
|
||||
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
||||
entry.getValue().writeTo(entry.getKey(), output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the set to a string in protocol buffer text format. This is
|
||||
* just a trivial wrapper around
|
||||
* {@link TextFormat#printToString(UnknownFieldSet)}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return TextFormat.printToString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code ByteString} and returns it. This is
|
||||
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public ByteString toByteString() {
|
||||
try {
|
||||
final ByteString.CodedBuilder out =
|
||||
ByteString.newCodedBuilder(getSerializedSize());
|
||||
writeTo(out.getCodedOutput());
|
||||
return out.build();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Serializing to a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message to a {@code byte} array and returns it. This is
|
||||
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
try {
|
||||
final byte[] result = new byte[getSerializedSize()];
|
||||
final CodedOutputStream output = CodedOutputStream.newInstance(result);
|
||||
writeTo(output);
|
||||
output.checkNoSpaceLeft();
|
||||
return result;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Serializing to a byte array threw an IOException " +
|
||||
"(should never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the message and writes it to {@code output}. This is just a
|
||||
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(final OutputStream output) throws IOException {
|
||||
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDelimitedTo(OutputStream output) throws IOException {
|
||||
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
|
||||
codedOutput.writeRawVarint32(getSerializedSize());
|
||||
writeTo(codedOutput);
|
||||
codedOutput.flush();
|
||||
}
|
||||
|
||||
/** Get the number of bytes required to encode this set. */
|
||||
@Override
|
||||
public int getSerializedSize() {
|
||||
int result = 0;
|
||||
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
||||
result += entry.getValue().getSerializedSize(entry.getKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the set and writes it to {@code output} using
|
||||
* {@code MessageSet} wire format.
|
||||
*/
|
||||
public void writeAsMessageSetTo(final CodedOutputStream output)
|
||||
throws IOException {
|
||||
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
||||
entry.getValue().writeAsMessageSetExtensionTo(
|
||||
entry.getKey(), output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes required to encode this set using
|
||||
* {@code MessageSet} wire format.
|
||||
*/
|
||||
public int getSerializedSizeAsMessageSet() {
|
||||
int result = 0;
|
||||
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
|
||||
result += entry.getValue().getSerializedSizeAsMessageSetExtension(
|
||||
entry.getKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
// UnknownFieldSets do not have required fields, so they are always
|
||||
// initialized.
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Parse an {@code UnknownFieldSet} from the given input stream. */
|
||||
public static UnknownFieldSet parseFrom(final CodedInputStream input)
|
||||
throws IOException {
|
||||
return newBuilder().mergeFrom(input).build();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
|
||||
public static UnknownFieldSet parseFrom(final ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).build();
|
||||
}
|
||||
|
||||
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
|
||||
public static UnknownFieldSet parseFrom(final byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).build();
|
||||
}
|
||||
|
||||
/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
|
||||
public static UnknownFieldSet parseFrom(final InputStream input)
|
||||
throws IOException {
|
||||
return newBuilder().mergeFrom(input).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder newBuilderForType() {
|
||||
return newBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return newBuilder().mergeFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link UnknownFieldSet}s.
|
||||
*
|
||||
* <p>Note that this class maintains {@link Field.Builder}s for all fields
|
||||
* in the set. Thus, adding one element to an existing {@link Field} does not
|
||||
* require making a copy. This is important for efficient parsing of
|
||||
* unknown repeated fields. However, it implies that {@link Field}s cannot
|
||||
* be constructed independently, nor can two {@link UnknownFieldSet}s share
|
||||
* the same {@code Field} object.
|
||||
*
|
||||
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
|
||||
*/
|
||||
public static final class Builder implements MessageLite.Builder {
|
||||
// This constructor should never be called directly (except from 'create').
|
||||
private Builder() {}
|
||||
|
||||
private Map<Integer, Field> fields;
|
||||
|
||||
// Optimization: We keep around a builder for the last field that was
|
||||
// modified so that we can efficiently add to it multiple times in a
|
||||
// row (important when parsing an unknown repeated field).
|
||||
private int lastFieldNumber;
|
||||
private Field.Builder lastField;
|
||||
|
||||
private static Builder create() {
|
||||
Builder builder = new Builder();
|
||||
builder.reinitialize();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field builder for the given field number which includes any
|
||||
* values that already exist.
|
||||
*/
|
||||
private Field.Builder getFieldBuilder(final int number) {
|
||||
if (lastField != null) {
|
||||
if (number == lastFieldNumber) {
|
||||
return lastField;
|
||||
}
|
||||
// Note: addField() will reset lastField and lastFieldNumber.
|
||||
addField(lastFieldNumber, lastField.build());
|
||||
}
|
||||
if (number == 0) {
|
||||
return null;
|
||||
} else {
|
||||
final Field existing = fields.get(number);
|
||||
lastFieldNumber = number;
|
||||
lastField = Field.newBuilder();
|
||||
if (existing != null) {
|
||||
lastField.mergeFrom(existing);
|
||||
}
|
||||
return lastField;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link UnknownFieldSet} and return it.
|
||||
*
|
||||
* <p>Once {@code build()} has been called, the {@code Builder} will no
|
||||
* longer be usable. Calling any method after {@code build()} will result
|
||||
* in undefined behavior and can cause a {@code NullPointerException} to be
|
||||
* thrown.
|
||||
*/
|
||||
@Override
|
||||
public UnknownFieldSet build() {
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
final UnknownFieldSet result;
|
||||
if (fields.isEmpty()) {
|
||||
result = getDefaultInstance();
|
||||
} else {
|
||||
result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
|
||||
}
|
||||
fields = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet buildPartial() {
|
||||
// No required fields, so this is the same as build().
|
||||
return build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clone() {
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
return UnknownFieldSet.newBuilder().mergeFrom(
|
||||
new UnknownFieldSet(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnknownFieldSet getDefaultInstanceForType() {
|
||||
return UnknownFieldSet.getDefaultInstance();
|
||||
}
|
||||
|
||||
private void reinitialize() {
|
||||
fields = Collections.emptyMap();
|
||||
lastFieldNumber = 0;
|
||||
lastField = null;
|
||||
}
|
||||
|
||||
/** Reset the builder to an empty set. */
|
||||
@Override
|
||||
public Builder clear() {
|
||||
reinitialize();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the fields from {@code other} into this set. If a field number
|
||||
* exists in both sets, {@code other}'s values for that field will be
|
||||
* appended to the values in this set.
|
||||
*/
|
||||
public Builder mergeFrom(final UnknownFieldSet other) {
|
||||
if (other != getDefaultInstance()) {
|
||||
for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
|
||||
mergeField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the {@code UnknownFieldSet}. If a field with the same
|
||||
* number already exists, the two are merged.
|
||||
*/
|
||||
public Builder mergeField(final int number, final Field field) {
|
||||
if (number == 0) {
|
||||
throw new IllegalArgumentException("Zero is not a valid field number.");
|
||||
}
|
||||
if (hasField(number)) {
|
||||
getFieldBuilder(number).mergeFrom(field);
|
||||
} else {
|
||||
// Optimization: We could call getFieldBuilder(number).mergeFrom(field)
|
||||
// in this case, but that would create a copy of the Field object.
|
||||
// We'd rather reuse the one passed to us, so call addField() instead.
|
||||
addField(number, field);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for merging a new field containing a single varint
|
||||
* value. This is used in particular when an unknown enum value is
|
||||
* encountered.
|
||||
*/
|
||||
public Builder mergeVarintField(final int number, final int value) {
|
||||
if (number == 0) {
|
||||
throw new IllegalArgumentException("Zero is not a valid field number.");
|
||||
}
|
||||
getFieldBuilder(number).addVarint(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Check if the given field number is present in the set. */
|
||||
public boolean hasField(final int number) {
|
||||
if (number == 0) {
|
||||
throw new IllegalArgumentException("Zero is not a valid field number.");
|
||||
}
|
||||
return number == lastFieldNumber || fields.containsKey(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the {@code UnknownFieldSet}. If a field with the same
|
||||
* number already exists, it is removed.
|
||||
*/
|
||||
public Builder addField(final int number, final Field field) {
|
||||
if (number == 0) {
|
||||
throw new IllegalArgumentException("Zero is not a valid field number.");
|
||||
}
|
||||
if (lastField != null && lastFieldNumber == number) {
|
||||
// Discard this.
|
||||
lastField = null;
|
||||
lastFieldNumber = 0;
|
||||
}
|
||||
if (fields.isEmpty()) {
|
||||
fields = new TreeMap<Integer,Field>();
|
||||
}
|
||||
fields.put(number, field);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all present {@code Field}s as an immutable {@code Map}. If more
|
||||
* fields are added, the changes may or may not be reflected in this map.
|
||||
*/
|
||||
public Map<Integer, Field> asMap() {
|
||||
getFieldBuilder(0); // Force lastField to be built.
|
||||
return Collections.unmodifiableMap(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an entire message from {@code input} and merge its fields into
|
||||
* this set.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final CodedInputStream input) throws IOException {
|
||||
while (true) {
|
||||
final int tag = input.readTag();
|
||||
if (tag == 0 || !mergeFieldFrom(tag, input)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single field from {@code input} and merge it into this set.
|
||||
* @param tag The field's tag number, which was already parsed.
|
||||
* @return {@code false} if the tag is an engroup tag.
|
||||
*/
|
||||
public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
|
||||
throws IOException {
|
||||
final int number = WireFormat.getTagFieldNumber(tag);
|
||||
switch (WireFormat.getTagWireType(tag)) {
|
||||
case WireFormat.WIRETYPE_VARINT:
|
||||
getFieldBuilder(number).addVarint(input.readInt64());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_FIXED64:
|
||||
getFieldBuilder(number).addFixed64(input.readFixed64());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
|
||||
getFieldBuilder(number).addLengthDelimited(input.readBytes());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_START_GROUP:
|
||||
final Builder subBuilder = newBuilder();
|
||||
input.readGroup(number, subBuilder,
|
||||
ExtensionRegistry.getEmptyRegistry());
|
||||
getFieldBuilder(number).addGroup(subBuilder.build());
|
||||
return true;
|
||||
case WireFormat.WIRETYPE_END_GROUP:
|
||||
return false;
|
||||
case WireFormat.WIRETYPE_FIXED32:
|
||||
getFieldBuilder(number).addFixed32(input.readFixed32());
|
||||
return true;
|
||||
default:
|
||||
throw InvalidProtocolBufferException.invalidWireType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
|
||||
* set being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final ByteString data)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = data.newCodedInput();
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return this;
|
||||
} catch (final InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a ByteString threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
|
||||
* set being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final byte[] data)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input = CodedInputStream.newInstance(data);
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return this;
|
||||
} catch (final InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a byte array threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
|
||||
* set being built. This is just a small wrapper around
|
||||
* {@link #mergeFrom(CodedInputStream)}.
|
||||
*/
|
||||
@Override
|
||||
public Builder mergeFrom(final InputStream input) throws IOException {
|
||||
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
|
||||
mergeFrom(codedInput);
|
||||
codedInput.checkLastTagWas(0);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(InputStream input)
|
||||
throws IOException {
|
||||
final int firstByte = input.read();
|
||||
if (firstByte == -1) {
|
||||
return false;
|
||||
}
|
||||
final int size = CodedInputStream.readRawVarint32(firstByte, input);
|
||||
final InputStream limitedInput = new LimitedInputStream(input, size);
|
||||
mergeFrom(limitedInput);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mergeDelimitedFrom(
|
||||
InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
// UnknownFieldSet has no extensions.
|
||||
return mergeDelimitedFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(
|
||||
CodedInputStream input,
|
||||
ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
// UnknownFieldSet has no extensions.
|
||||
return mergeFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(
|
||||
ByteString data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
// UnknownFieldSet has no extensions.
|
||||
return mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(byte[] data, int off, int len)
|
||||
throws InvalidProtocolBufferException {
|
||||
try {
|
||||
final CodedInputStream input =
|
||||
CodedInputStream.newInstance(data, off, len);
|
||||
mergeFrom(input);
|
||||
input.checkLastTagWas(0);
|
||||
return this;
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Reading from a byte array threw an IOException (should " +
|
||||
"never happen).", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(
|
||||
byte[] data,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
// UnknownFieldSet has no extensions.
|
||||
return mergeFrom(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(
|
||||
byte[] data, int off, int len,
|
||||
ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
// UnknownFieldSet has no extensions.
|
||||
return mergeFrom(data, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder mergeFrom(
|
||||
InputStream input,
|
||||
ExtensionRegistryLite extensionRegistry) throws IOException {
|
||||
// UnknownFieldSet has no extensions.
|
||||
return mergeFrom(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
// UnknownFieldSets do not have required fields, so they are always
|
||||
// initialized.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single field in an {@code UnknownFieldSet}.
|
||||
*
|
||||
* <p>A {@code Field} consists of five lists of values. The lists correspond
|
||||
* to the five "wire types" used in the protocol buffer binary format.
|
||||
* The wire type of each field can be determined from the encoded form alone,
|
||||
* without knowing the field's declared type. So, we are able to parse
|
||||
* unknown values at least this far and separate them. Normally, only one
|
||||
* of the five lists will contain any values, since it is impossible to
|
||||
* define a valid message type that declares two different types for the
|
||||
* same field number. However, the code is designed to allow for the case
|
||||
* where the same unknown field number is encountered using multiple different
|
||||
* wire types.
|
||||
*
|
||||
* <p>{@code Field} is an immutable class. To construct one, you must use a
|
||||
* {@link Builder}.
|
||||
*
|
||||
* @see UnknownFieldSet
|
||||
*/
|
||||
public static final class Field {
|
||||
private Field() {}
|
||||
|
||||
/** Construct a new {@link Builder}. */
|
||||
public static Builder newBuilder() {
|
||||
return Builder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link Builder} and initialize it to a copy of
|
||||
* {@code copyFrom}.
|
||||
*/
|
||||
public static Builder newBuilder(final Field copyFrom) {
|
||||
return newBuilder().mergeFrom(copyFrom);
|
||||
}
|
||||
|
||||
/** Get an empty {@code Field}. */
|
||||
public static Field getDefaultInstance() {
|
||||
return fieldDefaultInstance;
|
||||
}
|
||||
private static final Field fieldDefaultInstance = newBuilder().build();
|
||||
|
||||
/** Get the list of varint values for this field. */
|
||||
public List<Long> getVarintList() { return varint; }
|
||||
|
||||
/** Get the list of fixed32 values for this field. */
|
||||
public List<Integer> getFixed32List() { return fixed32; }
|
||||
|
||||
/** Get the list of fixed64 values for this field. */
|
||||
public List<Long> getFixed64List() { return fixed64; }
|
||||
|
||||
/** Get the list of length-delimited values for this field. */
|
||||
public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
|
||||
|
||||
/**
|
||||
* Get the list of embedded group values for this field. These are
|
||||
* represented using {@link UnknownFieldSet}s rather than {@link Message}s
|
||||
* since the group's type is presumably unknown.
|
||||
*/
|
||||
public List<UnknownFieldSet> getGroupList() { return group; }
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof Field)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(getIdentityArray(),
|
||||
((Field) other).getIdentityArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(getIdentityArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of objects to be used to uniquely identify this
|
||||
* {@link Field} instance.
|
||||
*/
|
||||
private Object[] getIdentityArray() {
|
||||
return new Object[] {
|
||||
varint,
|
||||
fixed32,
|
||||
fixed64,
|
||||
lengthDelimited,
|
||||
group};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the field, including field number, and writes it to
|
||||
* {@code output}.
|
||||
*/
|
||||
public void writeTo(final int fieldNumber, final CodedOutputStream output)
|
||||
throws IOException {
|
||||
for (final long value : varint) {
|
||||
output.writeUInt64(fieldNumber, value);
|
||||
}
|
||||
for (final int value : fixed32) {
|
||||
output.writeFixed32(fieldNumber, value);
|
||||
}
|
||||
for (final long value : fixed64) {
|
||||
output.writeFixed64(fieldNumber, value);
|
||||
}
|
||||
for (final ByteString value : lengthDelimited) {
|
||||
output.writeBytes(fieldNumber, value);
|
||||
}
|
||||
for (final UnknownFieldSet value : group) {
|
||||
output.writeGroup(fieldNumber, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes required to encode this field, including field
|
||||
* number.
|
||||
*/
|
||||
public int getSerializedSize(final int fieldNumber) {
|
||||
int result = 0;
|
||||
for (final long value : varint) {
|
||||
result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
|
||||
}
|
||||
for (final int value : fixed32) {
|
||||
result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
|
||||
}
|
||||
for (final long value : fixed64) {
|
||||
result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
|
||||
}
|
||||
for (final ByteString value : lengthDelimited) {
|
||||
result += CodedOutputStream.computeBytesSize(fieldNumber, value);
|
||||
}
|
||||
for (final UnknownFieldSet value : group) {
|
||||
result += CodedOutputStream.computeGroupSize(fieldNumber, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the field, including field number, and writes it to
|
||||
* {@code output}, using {@code MessageSet} wire format.
|
||||
*/
|
||||
public void writeAsMessageSetExtensionTo(
|
||||
final int fieldNumber,
|
||||
final CodedOutputStream output)
|
||||
throws IOException {
|
||||
for (final ByteString value : lengthDelimited) {
|
||||
output.writeRawMessageSetExtension(fieldNumber, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes required to encode this field, including field
|
||||
* number, using {@code MessageSet} wire format.
|
||||
*/
|
||||
public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
|
||||
int result = 0;
|
||||
for (final ByteString value : lengthDelimited) {
|
||||
result += CodedOutputStream.computeRawMessageSetExtensionSize(
|
||||
fieldNumber, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Long> varint;
|
||||
private List<Integer> fixed32;
|
||||
private List<Long> fixed64;
|
||||
private List<ByteString> lengthDelimited;
|
||||
private List<UnknownFieldSet> group;
|
||||
|
||||
/**
|
||||
* Used to build a {@link Field} within an {@link UnknownFieldSet}.
|
||||
*
|
||||
* <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
// This constructor should never be called directly (except from 'create').
|
||||
private Builder() {}
|
||||
|
||||
private static Builder create() {
|
||||
Builder builder = new Builder();
|
||||
builder.result = new Field();
|
||||
return builder;
|
||||
}
|
||||
|
||||
private Field result;
|
||||
|
||||
/**
|
||||
* Build the field. After {@code build()} has been called, the
|
||||
* {@code Builder} is no longer usable. Calling any other method will
|
||||
* result in undefined behavior and can cause a
|
||||
* {@code NullPointerException} to be thrown.
|
||||
*/
|
||||
public Field build() {
|
||||
if (result.varint == null) {
|
||||
result.varint = Collections.emptyList();
|
||||
} else {
|
||||
result.varint = Collections.unmodifiableList(result.varint);
|
||||
}
|
||||
if (result.fixed32 == null) {
|
||||
result.fixed32 = Collections.emptyList();
|
||||
} else {
|
||||
result.fixed32 = Collections.unmodifiableList(result.fixed32);
|
||||
}
|
||||
if (result.fixed64 == null) {
|
||||
result.fixed64 = Collections.emptyList();
|
||||
} else {
|
||||
result.fixed64 = Collections.unmodifiableList(result.fixed64);
|
||||
}
|
||||
if (result.lengthDelimited == null) {
|
||||
result.lengthDelimited = Collections.emptyList();
|
||||
} else {
|
||||
result.lengthDelimited =
|
||||
Collections.unmodifiableList(result.lengthDelimited);
|
||||
}
|
||||
if (result.group == null) {
|
||||
result.group = Collections.emptyList();
|
||||
} else {
|
||||
result.group = Collections.unmodifiableList(result.group);
|
||||
}
|
||||
|
||||
final Field returnMe = result;
|
||||
result = null;
|
||||
return returnMe;
|
||||
}
|
||||
|
||||
/** Discard the field's contents. */
|
||||
public Builder clear() {
|
||||
result = new Field();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the values in {@code other} into this field. For each list
|
||||
* of values, {@code other}'s values are append to the ones in this
|
||||
* field.
|
||||
*/
|
||||
public Builder mergeFrom(final Field other) {
|
||||
if (!other.varint.isEmpty()) {
|
||||
if (result.varint == null) {
|
||||
result.varint = new ArrayList<Long>();
|
||||
}
|
||||
result.varint.addAll(other.varint);
|
||||
}
|
||||
if (!other.fixed32.isEmpty()) {
|
||||
if (result.fixed32 == null) {
|
||||
result.fixed32 = new ArrayList<Integer>();
|
||||
}
|
||||
result.fixed32.addAll(other.fixed32);
|
||||
}
|
||||
if (!other.fixed64.isEmpty()) {
|
||||
if (result.fixed64 == null) {
|
||||
result.fixed64 = new ArrayList<Long>();
|
||||
}
|
||||
result.fixed64.addAll(other.fixed64);
|
||||
}
|
||||
if (!other.lengthDelimited.isEmpty()) {
|
||||
if (result.lengthDelimited == null) {
|
||||
result.lengthDelimited = new ArrayList<ByteString>();
|
||||
}
|
||||
result.lengthDelimited.addAll(other.lengthDelimited);
|
||||
}
|
||||
if (!other.group.isEmpty()) {
|
||||
if (result.group == null) {
|
||||
result.group = new ArrayList<UnknownFieldSet>();
|
||||
}
|
||||
result.group.addAll(other.group);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add a varint value. */
|
||||
public Builder addVarint(final long value) {
|
||||
if (result.varint == null) {
|
||||
result.varint = new ArrayList<Long>();
|
||||
}
|
||||
result.varint.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add a fixed32 value. */
|
||||
public Builder addFixed32(final int value) {
|
||||
if (result.fixed32 == null) {
|
||||
result.fixed32 = new ArrayList<Integer>();
|
||||
}
|
||||
result.fixed32.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add a fixed64 value. */
|
||||
public Builder addFixed64(final long value) {
|
||||
if (result.fixed64 == null) {
|
||||
result.fixed64 = new ArrayList<Long>();
|
||||
}
|
||||
result.fixed64.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add a length-delimited value. */
|
||||
public Builder addLengthDelimited(final ByteString value) {
|
||||
if (result.lengthDelimited == null) {
|
||||
result.lengthDelimited = new ArrayList<ByteString>();
|
||||
}
|
||||
result.lengthDelimited.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Add an embedded group. */
|
||||
public Builder addGroup(final UnknownFieldSet value) {
|
||||
if (result.group == null) {
|
||||
result.group = new ArrayList<UnknownFieldSet>();
|
||||
}
|
||||
result.group.add(value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
166
OsmAnd-java/src/com/google/protobuf/WireFormat.java
Normal file
166
OsmAnd-java/src/com/google/protobuf/WireFormat.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/**
|
||||
* This class is used internally by the Protocol Buffer library and generated
|
||||
* message implementations. It is public only because those generated messages
|
||||
* do not reside in the {@code protobuf} package. Others should not use this
|
||||
* class directly.
|
||||
*
|
||||
* This class contains constants and helper functions useful for dealing with
|
||||
* the Protocol Buffer wire format.
|
||||
*
|
||||
* @author kenton@google.com Kenton Varda
|
||||
*/
|
||||
public final class WireFormat {
|
||||
// Do not allow instantiation.
|
||||
private WireFormat() {}
|
||||
|
||||
static final int WIRETYPE_VARINT = 0;
|
||||
static final int WIRETYPE_FIXED64 = 1;
|
||||
static final int WIRETYPE_LENGTH_DELIMITED = 2;
|
||||
static final int WIRETYPE_START_GROUP = 3;
|
||||
static final int WIRETYPE_END_GROUP = 4;
|
||||
static final int WIRETYPE_FIXED32 = 5;
|
||||
// Osmand Delta change
|
||||
public static final int WIRETYPE_FIXED32_LENGTH_DELIMITED = 6;
|
||||
|
||||
static final int TAG_TYPE_BITS = 3;
|
||||
static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
|
||||
|
||||
/** Given a tag value, determines the wire type (the lower 3 bits). */
|
||||
public static int getTagWireType(final int tag) {
|
||||
return tag & TAG_TYPE_MASK;
|
||||
}
|
||||
|
||||
/** Given a tag value, determines the field number (the upper 29 bits). */
|
||||
public static int getTagFieldNumber(final int tag) {
|
||||
return tag >>> TAG_TYPE_BITS;
|
||||
}
|
||||
|
||||
/** Makes a tag value given a field number and wire type. */
|
||||
static int makeTag(final int fieldNumber, final int wireType) {
|
||||
return (fieldNumber << TAG_TYPE_BITS) | wireType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is
|
||||
* only here to support the lite runtime and should not be used by users.
|
||||
*/
|
||||
public enum JavaType {
|
||||
INT(0),
|
||||
LONG(0L),
|
||||
FLOAT(0F),
|
||||
DOUBLE(0D),
|
||||
BOOLEAN(false),
|
||||
STRING(""),
|
||||
BYTE_STRING(ByteString.EMPTY),
|
||||
ENUM(null),
|
||||
MESSAGE(null);
|
||||
|
||||
JavaType(final Object defaultDefault) {
|
||||
this.defaultDefault = defaultDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default default value for fields of this type, if it's a primitive
|
||||
* type.
|
||||
*/
|
||||
Object getDefaultDefault() {
|
||||
return defaultDefault;
|
||||
}
|
||||
|
||||
private final Object defaultDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is
|
||||
* only here to support the lite runtime and should not be used by users.
|
||||
*/
|
||||
public enum FieldType {
|
||||
DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ),
|
||||
FLOAT (JavaType.FLOAT , WIRETYPE_FIXED32 ),
|
||||
INT64 (JavaType.LONG , WIRETYPE_VARINT ),
|
||||
UINT64 (JavaType.LONG , WIRETYPE_VARINT ),
|
||||
INT32 (JavaType.INT , WIRETYPE_VARINT ),
|
||||
FIXED64 (JavaType.LONG , WIRETYPE_FIXED64 ),
|
||||
FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
|
||||
BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
|
||||
// OSMAND FIX no methods override for enum
|
||||
STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED, false),
|
||||
GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP , false),
|
||||
MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED , false),
|
||||
BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED , false),
|
||||
UINT32 (JavaType.INT , WIRETYPE_VARINT ),
|
||||
ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
|
||||
SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ),
|
||||
SFIXED64(JavaType.LONG , WIRETYPE_FIXED64 ),
|
||||
SINT32 (JavaType.INT , WIRETYPE_VARINT ),
|
||||
SINT64 (JavaType.LONG , WIRETYPE_VARINT );
|
||||
|
||||
FieldType(final JavaType javaType, final int wireType) {
|
||||
this.javaType = javaType;
|
||||
this.wireType = wireType;
|
||||
this.packable = true;
|
||||
}
|
||||
|
||||
FieldType(final JavaType javaType, final int wireType, boolean packable) {
|
||||
this.javaType = javaType;
|
||||
this.wireType = wireType;
|
||||
this.packable = packable;
|
||||
}
|
||||
|
||||
private final JavaType javaType;
|
||||
private final int wireType;
|
||||
private final boolean packable;
|
||||
|
||||
public JavaType getJavaType() { return javaType; }
|
||||
public int getWireType() { return wireType; }
|
||||
|
||||
public boolean isPackable() { return true; }
|
||||
}
|
||||
|
||||
// Field numbers for feilds in MessageSet wire format.
|
||||
static final int MESSAGE_SET_ITEM = 1;
|
||||
static final int MESSAGE_SET_TYPE_ID = 2;
|
||||
static final int MESSAGE_SET_MESSAGE = 3;
|
||||
|
||||
// Tag numbers.
|
||||
static final int MESSAGE_SET_ITEM_TAG =
|
||||
makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
|
||||
static final int MESSAGE_SET_ITEM_END_TAG =
|
||||
makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
|
||||
static final int MESSAGE_SET_TYPE_ID_TAG =
|
||||
makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
|
||||
static final int MESSAGE_SET_MESSAGE_TAG =
|
||||
makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
|
||||
}
|
18
OsmAnd-java/src/net/osmand/CallbackWithObject.java
Normal file
18
OsmAnd-java/src/net/osmand/CallbackWithObject.java
Normal file
|
@ -0,0 +1,18 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* That class is designed to be common interface for callbacks with one param
|
||||
* @author victor
|
||||
* @param <T>
|
||||
*/
|
||||
public interface CallbackWithObject<T> {
|
||||
|
||||
|
||||
/**
|
||||
* Calls on processing result
|
||||
* @param result could be null depends on usage
|
||||
* @return processed or not
|
||||
*/
|
||||
public boolean processResult(T result);
|
||||
|
||||
}
|
11
OsmAnd-java/src/net/osmand/Collator.java
Normal file
11
OsmAnd-java/src/net/osmand/Collator.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* Wrapper of java.text. Collator
|
||||
*/
|
||||
public interface Collator extends java.util.Comparator<Object>, Cloneable{
|
||||
|
||||
public boolean equals(String source, String target);
|
||||
|
||||
public abstract int compare(String source, String target);
|
||||
}
|
129
OsmAnd-java/src/net/osmand/CollatorStringMatcher.java
Normal file
129
OsmAnd-java/src/net/osmand/CollatorStringMatcher.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
package net.osmand;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Abstract collator matcher that basically supports subclasses with some collator
|
||||
* matching.
|
||||
*
|
||||
* @author pavol.zibrita
|
||||
*/
|
||||
public class CollatorStringMatcher implements StringMatcher {
|
||||
|
||||
private final Collator collator;
|
||||
private final StringMatcherMode mode;
|
||||
private final String part;
|
||||
|
||||
public static enum StringMatcherMode {
|
||||
CHECK_ONLY_STARTS_WITH,
|
||||
CHECK_STARTS_FROM_SPACE,
|
||||
CHECK_STARTS_FROM_SPACE_NOT_BEGINNING,
|
||||
CHECK_CONTAINS
|
||||
}
|
||||
|
||||
public CollatorStringMatcher(String part, StringMatcherMode mode) {
|
||||
this.collator = PlatformUtil.primaryCollator();
|
||||
this.part = part;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Collator getCollator() {
|
||||
return collator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String name) {
|
||||
return cmatches(collator, name, part, mode);
|
||||
}
|
||||
|
||||
|
||||
public static boolean cmatches(Collator collator, String base, String part, StringMatcherMode mode){
|
||||
switch (mode) {
|
||||
case CHECK_CONTAINS:
|
||||
return ccontains(collator, base, part);
|
||||
case CHECK_STARTS_FROM_SPACE:
|
||||
return cstartsWith(collator, base, part, true, true);
|
||||
case CHECK_STARTS_FROM_SPACE_NOT_BEGINNING:
|
||||
return cstartsWith(collator, base, part, false, true);
|
||||
case CHECK_ONLY_STARTS_WITH:
|
||||
return cstartsWith(collator, base, part, true, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if part contains in base
|
||||
*
|
||||
* @param collator Collator to use
|
||||
* @param part String to search
|
||||
* @param base String where to search
|
||||
* @return true if part is contained in base
|
||||
*/
|
||||
public static boolean ccontains(Collator collator, String base, String part) {
|
||||
int pos = 0;
|
||||
if (part.length() > 3) {
|
||||
// improve searching by searching first 3 characters
|
||||
pos = cindexOf(collator, pos, part.substring(0, 3), base);
|
||||
if (pos == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pos = cindexOf(collator, pos, part, base);
|
||||
if (pos == -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int cindexOf(Collator collator, int start, String part, String base) {
|
||||
for (int pos = start; pos <= base.length() - part.length(); pos++) {
|
||||
if (collator.equals(base.substring(pos, pos + part.length()), part)) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string starts with another string.
|
||||
* Special check try to find as well in the middle of name
|
||||
*
|
||||
* @param collator
|
||||
* @param searchIn
|
||||
* @param theStart
|
||||
* @return true if searchIn starts with token
|
||||
*/
|
||||
public static boolean cstartsWith(Collator collator, String searchIn, String theStart,
|
||||
boolean checkBeginning, boolean checkSpaces) {
|
||||
int startLength = theStart.length();
|
||||
int searchInLength = searchIn.length();
|
||||
if (startLength == 0) {
|
||||
return true;
|
||||
}
|
||||
if (startLength > searchInLength) {
|
||||
return false;
|
||||
}
|
||||
// simulate starts with for collator
|
||||
if (checkBeginning) {
|
||||
boolean starts = collator.equals(searchIn.substring(0, startLength), theStart);
|
||||
if (starts) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (checkSpaces) {
|
||||
for (int i = 1; i <= searchInLength - startLength; i++) {
|
||||
if (isSpace(searchIn.charAt(i - 1)) && !isSpace(searchIn.charAt(i))) {
|
||||
if (collator.equals(searchIn.substring(i, i + startLength), theStart)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isSpace(char c){
|
||||
return !Character.isLetter(c) && !Character.isDigit(c);
|
||||
}
|
||||
}
|
38
OsmAnd-java/src/net/osmand/FloatMath.java
Normal file
38
OsmAnd-java/src/net/osmand/FloatMath.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* This class can be replaced with more effective on ARM devices
|
||||
*/
|
||||
public class FloatMath {
|
||||
|
||||
public static float PI = (float) Math.PI;
|
||||
|
||||
public static float cos(float a) {
|
||||
return (float) Math.cos(a);
|
||||
}
|
||||
|
||||
public static float sin(float a) {
|
||||
return (float) Math.sin(a);
|
||||
}
|
||||
|
||||
public static float abs(float a) {
|
||||
return (float) Math.abs(a);
|
||||
}
|
||||
|
||||
public static float atan2(float py, float px) {
|
||||
return (float) Math.atan2(py, px);
|
||||
}
|
||||
|
||||
public static float sqrt(float f) {
|
||||
return (float) Math.sqrt(f);
|
||||
}
|
||||
|
||||
public static float max(float a, float b) {
|
||||
if(a > b) {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
}
|
77
OsmAnd-java/src/net/osmand/GeoidAltitudeCorrection.java
Normal file
77
OsmAnd-java/src/net/osmand/GeoidAltitudeCorrection.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
package net.osmand;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
public class GeoidAltitudeCorrection {
|
||||
|
||||
private final Log log = PlatformUtil.getLog(GeoidAltitudeCorrection.class);
|
||||
private File f;
|
||||
private RandomAccessFile rf;
|
||||
|
||||
private int cachedPointer = -1;
|
||||
private short cachedValue = 0;
|
||||
|
||||
public GeoidAltitudeCorrection(File dir) {
|
||||
String[] fnames = dir.list();
|
||||
if(fnames != null) {
|
||||
String fn = null;
|
||||
for(String f : fnames) {
|
||||
if(f.contains("WW15MGH")) {
|
||||
fn = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fn != null) {
|
||||
this.f = new File(dir, fn);
|
||||
if (f.exists()) {
|
||||
try {
|
||||
rf = new RandomAccessFile(f.getPath(), "r");
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error("Error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isGeoidInformationAvailable(){
|
||||
return rf != null;
|
||||
}
|
||||
|
||||
public float getGeoidHeight(double lat, double lon) {
|
||||
if (!isGeoidInformationAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
int shy = (int) Math.floor((90 - lat) * 4);
|
||||
int shx = (int) Math.floor((lon >= 0 ? lon : lon + 360) * 4);
|
||||
int pointer = ((shy * 1440) + shx) * 2;
|
||||
short res = 0;
|
||||
if (pointer != cachedPointer) {
|
||||
try {
|
||||
rf.seek(pointer);
|
||||
// read short
|
||||
cachedValue = readShort();
|
||||
cachedPointer = pointer;
|
||||
} catch (IOException e) {
|
||||
log.error("Geoid info error", e);
|
||||
}
|
||||
}
|
||||
res = cachedValue;
|
||||
return res / 100f;
|
||||
}
|
||||
|
||||
private short readShort() throws IOException {
|
||||
byte[] b = new byte[2];
|
||||
rf.read(b);
|
||||
int ch1 = b[0] < 0 ? b[0] + 256 : b[0];
|
||||
int ch2 = b[1] < 0 ? b[1] + 256 : b[1];
|
||||
return (short)((ch1 << 8) + (ch2 << 0));
|
||||
}
|
||||
}
|
57
OsmAnd-java/src/net/osmand/IProgress.java
Normal file
57
OsmAnd-java/src/net/osmand/IProgress.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* That common interface that could be used by background operations.
|
||||
* Implementation of it depends on chosen UI platform
|
||||
*/
|
||||
public interface IProgress {
|
||||
|
||||
/**
|
||||
* @param taskName
|
||||
* @param work - -1 means that indeterminate task,
|
||||
* otherwise number of could be specified
|
||||
*/
|
||||
public void startTask(String taskName, int work);
|
||||
|
||||
public void startWork(int work);
|
||||
|
||||
public void progress(int deltaWork);
|
||||
|
||||
public void remaining(int remainingWork);
|
||||
|
||||
public void setGeneralProgress(String genProgress);
|
||||
|
||||
public void finishTask();
|
||||
|
||||
public boolean isIndeterminate();
|
||||
|
||||
public boolean isInterrupted();
|
||||
|
||||
public IProgress EMPTY_PROGRESS = new IProgress() {
|
||||
|
||||
@Override
|
||||
public void startWork(int work) {}
|
||||
|
||||
@Override
|
||||
public void startTask(String taskName, int work) {}
|
||||
|
||||
@Override
|
||||
public void setGeneralProgress(String genProgress) {}
|
||||
|
||||
@Override
|
||||
public void remaining(int remainingWork) {}
|
||||
|
||||
@Override
|
||||
public void progress(int deltaWork) {}
|
||||
|
||||
@Override
|
||||
public boolean isInterrupted() {return false;}
|
||||
|
||||
@Override
|
||||
public boolean isIndeterminate() {return false;}
|
||||
|
||||
@Override
|
||||
public void finishTask() {}
|
||||
};
|
||||
|
||||
}
|
48
OsmAnd-java/src/net/osmand/IndexConstants.java
Normal file
48
OsmAnd-java/src/net/osmand/IndexConstants.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
package net.osmand;
|
||||
|
||||
|
||||
public class IndexConstants {
|
||||
|
||||
// Important : Every time you change schema of db upgrade version!!!
|
||||
// If you want that new application support old index : put upgrade code in android app ResourceManager
|
||||
public final static int POI_TABLE_VERSION = 1;
|
||||
public final static int BINARY_MAP_VERSION = 2; // starts with 1
|
||||
public final static int VOICE_VERSION = 0; //supported download versions
|
||||
public final static int TTSVOICE_VERSION = 1; //supported download versions
|
||||
|
||||
public static final String POI_INDEX_EXT = ".poi.odb"; //$NON-NLS-1$
|
||||
public static final String BINARY_MAP_INDEX_EXT = ".obf"; //$NON-NLS-1$
|
||||
|
||||
public static final String GEN_LOG_EXT = ".gen.log"; //$NON-NLS-1$
|
||||
|
||||
public static final String POI_INDEX_EXT_ZIP = ".poi.zip"; //$NON-NLS-1$
|
||||
public static final String VOICE_INDEX_EXT_ZIP = ".voice.zip"; //$NON-NLS-1$
|
||||
public static final String TTSVOICE_INDEX_EXT_ZIP = ".ttsvoice.zip"; //$NON-NLS-1$
|
||||
public static final String ANYVOICE_INDEX_EXT_ZIP = "voice.zip"; //$NON-NLS-1$ //to cactch both voices, .voice.zip and .ttsvoice.zip
|
||||
public static final String BINARY_MAP_INDEX_EXT_ZIP = ".obf.zip"; //$NON-NLS-1$
|
||||
|
||||
public static final String EXTRA_ZIP_EXT = ".extra.zip";
|
||||
public static final String EXTRA_EXT = ".extra";
|
||||
|
||||
public static final String RENDERER_INDEX_EXT = ".render.xml"; //$NON-NLS-1$
|
||||
|
||||
public final static String POI_TABLE = "poi"; //$NON-NLS-1$
|
||||
|
||||
public static final String INDEX_DOWNLOAD_DOMAIN = "download.osmand.net";
|
||||
public static final String APP_DIR = "osmand/"; //$NON-NLS-1$
|
||||
public static final String MAPS_PATH = "";
|
||||
public static final String BACKUP_INDEX_DIR= "backup/";
|
||||
public static final String GPX_INDEX_DIR= "tracks/";
|
||||
public static final String TILES_INDEX_DIR= "tiles/";
|
||||
public static final String SRTM_INDEX_DIR = "srtm/"; //$NON-NLS-1$
|
||||
public static final String AV_INDEX_DIR = "avnotes/"; //$NON-NLS-1$
|
||||
public static final String VOICE_INDEX_DIR = "voice/"; //$NON-NLS-1$
|
||||
public static final String RENDERERS_DIR = "rendering/"; //$NON-NLS-1$
|
||||
public static final String ROUTING_XML_FILE= "routing.xml";
|
||||
|
||||
|
||||
public static final String SQLITE_EXT = ".sqlitedb"; //$NON-NLS-1$
|
||||
public static final String TEMP_SOURCE_TO_LOAD = "temp";
|
||||
|
||||
|
||||
}
|
514
OsmAnd-java/src/net/osmand/Location.java
Normal file
514
OsmAnd-java/src/net/osmand/Location.java
Normal file
|
@ -0,0 +1,514 @@
|
|||
package net.osmand;
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A class representing a geographic location sensed at a particular
|
||||
* time (a "fix"). A location consists of a latitude and longitude, a
|
||||
* UTC timestamp. and optionally information on altitude, speed, and
|
||||
* bearing.
|
||||
*
|
||||
* <p> Information specific to a particular provider or class of
|
||||
* providers may be communicated to the application using getExtras,
|
||||
* which returns a Bundle of key/value pairs. Each provider will only
|
||||
* provide those entries for which information is available.
|
||||
*/
|
||||
public class Location {
|
||||
|
||||
private String mProvider;
|
||||
private long mTime = 0;
|
||||
private double mLatitude = 0.0;
|
||||
private double mLongitude = 0.0;
|
||||
private boolean mHasAltitude = false;
|
||||
private double mAltitude = 0.0f;
|
||||
private boolean mHasSpeed = false;
|
||||
private float mSpeed = 0.0f;
|
||||
private boolean mHasBearing = false;
|
||||
private float mBearing = 0.0f;
|
||||
private boolean mHasAccuracy = false;
|
||||
private float mAccuracy = 0.0f;
|
||||
|
||||
// Cache the inputs and outputs of computeDistanceAndBearing
|
||||
// so calls to distanceTo() and bearingTo() can share work
|
||||
private double mLat1 = 0.0;
|
||||
private double mLon1 = 0.0;
|
||||
private double mLat2 = 0.0;
|
||||
private double mLon2 = 0.0;
|
||||
private float mDistance = 0.0f;
|
||||
private float mInitialBearing = 0.0f;
|
||||
// Scratchpad
|
||||
private float[] mResults = new float[2];
|
||||
|
||||
/**
|
||||
* Constructs a new Location. By default, time, latitude,
|
||||
* longitude, and numSatellites are 0; hasAltitude, hasSpeed, and
|
||||
* hasBearing are false; and there is no extra information.
|
||||
*
|
||||
* @param provider the name of the location provider that generated this
|
||||
* location fix.
|
||||
*/
|
||||
public Location(String provider) {
|
||||
mProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Location object that is a copy of the given
|
||||
* location.
|
||||
*/
|
||||
public Location(Location l) {
|
||||
set(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the contents of the location to the values from the given location.
|
||||
*/
|
||||
public void set(Location l) {
|
||||
mProvider = l.mProvider;
|
||||
mTime = l.mTime;
|
||||
mLatitude = l.mLatitude;
|
||||
mLongitude = l.mLongitude;
|
||||
mHasAltitude = l.mHasAltitude;
|
||||
mAltitude = l.mAltitude;
|
||||
mHasSpeed = l.mHasSpeed;
|
||||
mSpeed = l.mSpeed;
|
||||
mHasBearing = l.mHasBearing;
|
||||
mBearing = l.mBearing;
|
||||
mHasAccuracy = l.mHasAccuracy;
|
||||
mAccuracy = l.mAccuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the contents of the location.
|
||||
*/
|
||||
public void reset() {
|
||||
mProvider = null;
|
||||
mTime = 0;
|
||||
mLatitude = 0;
|
||||
mLongitude = 0;
|
||||
mHasAltitude = false;
|
||||
mAltitude = 0;
|
||||
mHasSpeed = false;
|
||||
mSpeed = 0;
|
||||
mHasBearing = false;
|
||||
mBearing = 0;
|
||||
mHasAccuracy = false;
|
||||
mAccuracy = 0;
|
||||
}
|
||||
|
||||
|
||||
private static void computeDistanceAndBearing(double lat1, double lon1,
|
||||
double lat2, double lon2, float[] results) {
|
||||
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
|
||||
// using the "Inverse Formula" (section 4)
|
||||
|
||||
int MAXITERS = 20;
|
||||
// Convert lat/long to radians
|
||||
lat1 *= Math.PI / 180.0;
|
||||
lat2 *= Math.PI / 180.0;
|
||||
lon1 *= Math.PI / 180.0;
|
||||
lon2 *= Math.PI / 180.0;
|
||||
|
||||
double a = 6378137.0; // WGS84 major axis
|
||||
double b = 6356752.3142; // WGS84 semi-major axis
|
||||
double f = (a - b) / a;
|
||||
double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
|
||||
|
||||
double L = lon2 - lon1;
|
||||
double A = 0.0;
|
||||
double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
|
||||
double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
|
||||
|
||||
double cosU1 = Math.cos(U1);
|
||||
double cosU2 = Math.cos(U2);
|
||||
double sinU1 = Math.sin(U1);
|
||||
double sinU2 = Math.sin(U2);
|
||||
double cosU1cosU2 = cosU1 * cosU2;
|
||||
double sinU1sinU2 = sinU1 * sinU2;
|
||||
|
||||
double sigma = 0.0;
|
||||
double deltaSigma = 0.0;
|
||||
double cosSqAlpha = 0.0;
|
||||
double cos2SM = 0.0;
|
||||
double cosSigma = 0.0;
|
||||
double sinSigma = 0.0;
|
||||
double cosLambda = 0.0;
|
||||
double sinLambda = 0.0;
|
||||
|
||||
double lambda = L; // initial guess
|
||||
for (int iter = 0; iter < MAXITERS; iter++) {
|
||||
double lambdaOrig = lambda;
|
||||
cosLambda = Math.cos(lambda);
|
||||
sinLambda = Math.sin(lambda);
|
||||
double t1 = cosU2 * sinLambda;
|
||||
double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
|
||||
double sinSqSigma = t1 * t1 + t2 * t2; // (14)
|
||||
sinSigma = Math.sqrt(sinSqSigma);
|
||||
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
|
||||
sigma = Math.atan2(sinSigma, cosSigma); // (16)
|
||||
double sinAlpha = (sinSigma == 0) ? 0.0 :
|
||||
cosU1cosU2 * sinLambda / sinSigma; // (17)
|
||||
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
|
||||
cos2SM = (cosSqAlpha == 0) ? 0.0 :
|
||||
cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
|
||||
|
||||
double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
|
||||
A = 1 + (uSquared / 16384.0) * // (3)
|
||||
(4096.0 + uSquared *
|
||||
(-768 + uSquared * (320.0 - 175.0 * uSquared)));
|
||||
double B = (uSquared / 1024.0) * // (4)
|
||||
(256.0 + uSquared *
|
||||
(-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
|
||||
double C = (f / 16.0) *
|
||||
cosSqAlpha *
|
||||
(4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
|
||||
double cos2SMSq = cos2SM * cos2SM;
|
||||
deltaSigma = B * sinSigma * // (6)
|
||||
(cos2SM + (B / 4.0) *
|
||||
(cosSigma * (-1.0 + 2.0 * cos2SMSq) -
|
||||
(B / 6.0) * cos2SM *
|
||||
(-3.0 + 4.0 * sinSigma * sinSigma) *
|
||||
(-3.0 + 4.0 * cos2SMSq)));
|
||||
|
||||
lambda = L +
|
||||
(1.0 - C) * f * sinAlpha *
|
||||
(sigma + C * sinSigma *
|
||||
(cos2SM + C * cosSigma *
|
||||
(-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
|
||||
|
||||
double delta = (lambda - lambdaOrig) / lambda;
|
||||
if (Math.abs(delta) < 1.0e-12) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float distance = (float) (b * A * (sigma - deltaSigma));
|
||||
results[0] = distance;
|
||||
if (results.length > 1) {
|
||||
float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
|
||||
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
|
||||
initialBearing *= 180.0 / Math.PI;
|
||||
results[1] = initialBearing;
|
||||
if (results.length > 2) {
|
||||
float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
|
||||
-sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
|
||||
finalBearing *= 180.0 / Math.PI;
|
||||
results[2] = finalBearing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the approximate distance in meters between two
|
||||
* locations, and optionally the initial and final bearings of the
|
||||
* shortest path between them. Distance and bearing are defined using the
|
||||
* WGS84 ellipsoid.
|
||||
*
|
||||
* <p> The computed distance is stored in results[0]. If results has length
|
||||
* 2 or greater, the initial bearing is stored in results[1]. If results has
|
||||
* length 3 or greater, the final bearing is stored in results[2].
|
||||
*
|
||||
* @param startLatitude the starting latitude
|
||||
* @param startLongitude the starting longitude
|
||||
* @param endLatitude the ending latitude
|
||||
* @param endLongitude the ending longitude
|
||||
* @param results an array of floats to hold the results
|
||||
*
|
||||
* @throws IllegalArgumentException if results is null or has length < 1
|
||||
*/
|
||||
public static void distanceBetween(double startLatitude, double startLongitude,
|
||||
double endLatitude, double endLongitude, float[] results) {
|
||||
if (results == null || results.length < 1) {
|
||||
throw new IllegalArgumentException("results is null or has length < 1");
|
||||
}
|
||||
computeDistanceAndBearing(startLatitude, startLongitude,
|
||||
endLatitude, endLongitude, results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the approximate distance in meters between this
|
||||
* location and the given location. Distance is defined using
|
||||
* the WGS84 ellipsoid.
|
||||
*
|
||||
* @param dest the destination location
|
||||
* @return the approximate distance in meters
|
||||
*/
|
||||
public float distanceTo(Location dest) {
|
||||
// See if we already have the result
|
||||
synchronized (mResults) {
|
||||
if (mLatitude != mLat1 || mLongitude != mLon1 ||
|
||||
dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
|
||||
computeDistanceAndBearing(mLatitude, mLongitude,
|
||||
dest.mLatitude, dest.mLongitude, mResults);
|
||||
mLat1 = mLatitude;
|
||||
mLon1 = mLongitude;
|
||||
mLat2 = dest.mLatitude;
|
||||
mLon2 = dest.mLongitude;
|
||||
mDistance = mResults[0];
|
||||
mInitialBearing = mResults[1];
|
||||
}
|
||||
return mDistance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the approximate initial bearing in degrees East of true
|
||||
* North when traveling along the shortest path between this
|
||||
* location and the given location. The shortest path is defined
|
||||
* using the WGS84 ellipsoid. Locations that are (nearly)
|
||||
* antipodal may produce meaningless results.
|
||||
*
|
||||
* @param dest the destination location
|
||||
* @return the initial bearing in degrees
|
||||
*/
|
||||
public float bearingTo(Location dest) {
|
||||
synchronized (mResults) {
|
||||
// See if we already have the result
|
||||
if (mLatitude != mLat1 || mLongitude != mLon1 ||
|
||||
dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
|
||||
computeDistanceAndBearing(mLatitude, mLongitude,
|
||||
dest.mLatitude, dest.mLongitude, mResults);
|
||||
mLat1 = mLatitude;
|
||||
mLon1 = mLongitude;
|
||||
mLat2 = dest.mLatitude;
|
||||
mLon2 = dest.mLongitude;
|
||||
mDistance = mResults[0];
|
||||
mInitialBearing = mResults[1];
|
||||
}
|
||||
return mInitialBearing;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the provider that generated this fix,
|
||||
* or null if it is not associated with a provider.
|
||||
*/
|
||||
public String getProvider() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the provider that generated this fix.
|
||||
*/
|
||||
public void setProvider(String provider) {
|
||||
mProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC time of this fix, in milliseconds since January 1,
|
||||
* 1970.
|
||||
*/
|
||||
public long getTime() {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UTC time of this fix, in milliseconds since January 1,
|
||||
* 1970.
|
||||
*/
|
||||
public void setTime(long time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude of this fix.
|
||||
*/
|
||||
public double getLatitude() {
|
||||
return mLatitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the latitude of this fix.
|
||||
*/
|
||||
public void setLatitude(double latitude) {
|
||||
mLatitude = latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the longitude of this fix.
|
||||
*/
|
||||
public double getLongitude() {
|
||||
return mLongitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the longitude of this fix.
|
||||
*/
|
||||
public void setLongitude(double longitude) {
|
||||
mLongitude = longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this fix contains altitude information, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean hasAltitude() {
|
||||
return mHasAltitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the altitude of this fix. If {@link #hasAltitude} is false,
|
||||
* 0.0f is returned.
|
||||
*/
|
||||
public double getAltitude() {
|
||||
return mAltitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the altitude of this fix. Following this call,
|
||||
* hasAltitude() will return true.
|
||||
*/
|
||||
public void setAltitude(double altitude) {
|
||||
mAltitude = altitude;
|
||||
mHasAltitude = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the altitude of this fix. Following this call,
|
||||
* hasAltitude() will return false.
|
||||
*/
|
||||
public void removeAltitude() {
|
||||
mAltitude = 0.0f;
|
||||
mHasAltitude = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this fix contains speed information, false
|
||||
* otherwise. The default implementation returns false.
|
||||
*/
|
||||
public boolean hasSpeed() {
|
||||
return mHasSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the speed of the device over ground in meters/second.
|
||||
* If hasSpeed() is false, 0.0f is returned.
|
||||
*/
|
||||
public float getSpeed() {
|
||||
return mSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speed of this fix, in meters/second. Following this
|
||||
* call, hasSpeed() will return true.
|
||||
*/
|
||||
public void setSpeed(float speed) {
|
||||
mSpeed = speed;
|
||||
mHasSpeed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the speed of this fix. Following this call, hasSpeed()
|
||||
* will return false.
|
||||
*/
|
||||
public void removeSpeed() {
|
||||
mSpeed = 0.0f;
|
||||
mHasSpeed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to report bearing information,
|
||||
* false otherwise. The default implementation returns false.
|
||||
*/
|
||||
public boolean hasBearing() {
|
||||
return mHasBearing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the direction of travel in degrees East of true
|
||||
* North. If hasBearing() is false, 0.0 is returned.
|
||||
*/
|
||||
public float getBearing() {
|
||||
return mBearing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bearing of this fix. Following this call, hasBearing()
|
||||
* will return true.
|
||||
*/
|
||||
public void setBearing(float bearing) {
|
||||
while (bearing < 0.0f) {
|
||||
bearing += 360.0f;
|
||||
}
|
||||
while (bearing >= 360.0f) {
|
||||
bearing -= 360.0f;
|
||||
}
|
||||
mBearing = bearing;
|
||||
mHasBearing = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the bearing of this fix. Following this call, hasBearing()
|
||||
* will return false.
|
||||
*/
|
||||
public void removeBearing() {
|
||||
mBearing = 0.0f;
|
||||
mHasBearing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to report accuracy information,
|
||||
* false otherwise. The default implementation returns false.
|
||||
*/
|
||||
public boolean hasAccuracy() {
|
||||
return mHasAccuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accuracy of the fix in meters. If hasAccuracy() is false,
|
||||
* 0.0 is returned.
|
||||
*/
|
||||
public float getAccuracy() {
|
||||
return mAccuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accuracy of this fix. Following this call, hasAccuracy()
|
||||
* will return true.
|
||||
*/
|
||||
public void setAccuracy(float accuracy) {
|
||||
mAccuracy = accuracy;
|
||||
mHasAccuracy = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the accuracy of this fix. Following this call, hasAccuracy()
|
||||
* will return false.
|
||||
*/
|
||||
public void removeAccuracy() {
|
||||
mAccuracy = 0.0f;
|
||||
mHasAccuracy = false;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "Location[mProvider=" + mProvider +
|
||||
",mTime=" + mTime +
|
||||
",mLatitude=" + mLatitude +
|
||||
",mLongitude=" + mLongitude +
|
||||
",mHasAltitude=" + mHasAltitude +
|
||||
",mAltitude=" + mAltitude +
|
||||
",mHasSpeed=" + mHasSpeed +
|
||||
",mSpeed=" + mSpeed +
|
||||
",mHasBearing=" + mHasBearing +
|
||||
",mBearing=" + mBearing +
|
||||
",mHasAccuracy=" + mHasAccuracy +
|
||||
",mAccuracy=" + mAccuracy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
289
OsmAnd-java/src/net/osmand/NativeLibrary.java
Normal file
289
OsmAnd-java/src/net/osmand/NativeLibrary.java
Normal file
|
@ -0,0 +1,289 @@
|
|||
package net.osmand;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteSubregion;
|
||||
import net.osmand.binary.RouteDataObject;
|
||||
import net.osmand.render.RenderingRuleSearchRequest;
|
||||
import net.osmand.render.RenderingRulesStorage;
|
||||
import net.osmand.router.GeneralRouter;
|
||||
import net.osmand.router.RouteCalculationProgress;
|
||||
import net.osmand.router.RouteSegmentResult;
|
||||
import net.osmand.router.RoutingConfiguration;
|
||||
|
||||
public class NativeLibrary {
|
||||
|
||||
public static class RenderingGenerationResult {
|
||||
public RenderingGenerationResult(ByteBuffer bitmap) {
|
||||
bitmapBuffer = bitmap;
|
||||
}
|
||||
|
||||
public final ByteBuffer bitmapBuffer;
|
||||
}
|
||||
|
||||
public static class NativeSearchResult {
|
||||
|
||||
public long nativeHandler;
|
||||
|
||||
private NativeSearchResult(long nativeHandler) {
|
||||
this.nativeHandler = nativeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
deleteNativeResult();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void deleteNativeResult() {
|
||||
if (nativeHandler != 0) {
|
||||
deleteSearchResult(nativeHandler);
|
||||
nativeHandler = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class NativeRouteSearchResult {
|
||||
|
||||
public long nativeHandler;
|
||||
public RouteDataObject[] objects;
|
||||
public RouteSubregion region;
|
||||
|
||||
public NativeRouteSearchResult(long nativeHandler, RouteDataObject[] objects) {
|
||||
this.nativeHandler = nativeHandler;
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
deleteNativeResult();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void deleteNativeResult() {
|
||||
if (nativeHandler != 0) {
|
||||
deleteRouteSearchResult(nativeHandler);
|
||||
nativeHandler = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchResultHandle
|
||||
* - must be null if there is no need to append to previous results returns native handle to results
|
||||
*/
|
||||
public NativeSearchResult searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom,
|
||||
RenderingRuleSearchRequest request, boolean skipDuplicates, Object objectWithInterruptedField, String msgIfNothingFound) {
|
||||
int renderRouteDataFile = 0;
|
||||
if (request.searchRenderingAttribute("showRoadMapsAttribute")) {
|
||||
renderRouteDataFile = request.getIntPropertyValue(request.ALL.R_ATTR_INT_VALUE);
|
||||
}
|
||||
return new NativeSearchResult(searchNativeObjectsForRendering(sleft, sright, stop, sbottom, zoom, request, skipDuplicates,
|
||||
renderRouteDataFile, objectWithInterruptedField, msgIfNothingFound));
|
||||
}
|
||||
|
||||
public RouteDataObject[] getDataObjects(NativeRouteSearchResult rs, int x31, int y31) {
|
||||
if (rs.nativeHandler == 0) {
|
||||
// do not throw exception because it is expected situation
|
||||
return new RouteDataObject[0];
|
||||
}
|
||||
return getRouteDataObjects(rs.region.routeReg, rs.nativeHandler, x31, y31);
|
||||
}
|
||||
|
||||
public boolean initMapFile(String filePath) {
|
||||
return initBinaryMapFile(filePath);
|
||||
}
|
||||
|
||||
public boolean initCacheMapFile(String filePath) {
|
||||
return initCacheMapFiles(filePath);
|
||||
}
|
||||
|
||||
public boolean closeMapFile(String filePath) {
|
||||
return closeBinaryMapFile(filePath);
|
||||
}
|
||||
|
||||
public RouteSegmentResult[] runNativeRouting(int sx31, int sy31, int ex31, int ey31, RoutingConfiguration config,
|
||||
RouteRegion[] regions, RouteCalculationProgress progress) {
|
||||
TIntArrayList state = new TIntArrayList();
|
||||
List<String> keys = new ArrayList<String>();
|
||||
List<String> values = new ArrayList<String>();
|
||||
GeneralRouter r = (GeneralRouter) config.router;
|
||||
fillObjects(state, keys, values, 0, r.highwaySpeed);
|
||||
fillObjects(state, keys, values, 1, r.highwayPriorities);
|
||||
fillObjects(state, keys, values, 2, r.avoid);
|
||||
fillObjects(state, keys, values, 3, r.obstacles);
|
||||
fillObjects(state, keys, values, 4, r.routingObstacles);
|
||||
LinkedHashMap<String, String> attrs = new LinkedHashMap<String, String>(config.attributes);
|
||||
attrs.putAll(r.attributes);
|
||||
fillObjects(state, keys, values, 5, attrs);
|
||||
|
||||
return nativeRouting(new int[] { sx31, sy31, ex31, ey31 }, state.toArray(), keys.toArray(new String[keys.size()]),
|
||||
values.toArray(new String[values.size()]), config.initialDirection == null ? -360 : config.initialDirection.floatValue(),
|
||||
regions, progress);
|
||||
}
|
||||
|
||||
public <T> void fillObjects(TIntArrayList state, List<String> keys, List<String> values, int s, Map<String, T> map) {
|
||||
Iterator<Entry<String, T>> it = map.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<String, T> n = it.next();
|
||||
state.add(s);
|
||||
keys.add(n.getKey());
|
||||
values.add(n.getValue() + "");
|
||||
}
|
||||
}
|
||||
|
||||
public NativeRouteSearchResult loadRouteRegion(RouteSubregion sub, boolean loadObjects) {
|
||||
NativeRouteSearchResult lr = loadRoutingData(sub.routeReg, sub.routeReg.getName(), sub.routeReg.getFilePointer(), sub, loadObjects);
|
||||
if (lr != null && lr.nativeHandler != 0) {
|
||||
lr.region = sub;
|
||||
}
|
||||
return lr;
|
||||
}
|
||||
|
||||
/**/
|
||||
protected static native NativeRouteSearchResult loadRoutingData(RouteRegion reg, String regName, int regfp, RouteSubregion subreg,
|
||||
boolean loadObjects);
|
||||
|
||||
protected static native void deleteRouteSearchResult(long searchResultHandle);
|
||||
|
||||
protected static native RouteDataObject[] getRouteDataObjects(RouteRegion reg, long rs, int x31, int y31);
|
||||
|
||||
protected static native RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig,
|
||||
float initDirection, RouteRegion[] regions, RouteCalculationProgress progress);
|
||||
|
||||
protected static native void deleteSearchResult(long searchResultHandle);
|
||||
|
||||
protected static native boolean initBinaryMapFile(String filePath);
|
||||
|
||||
protected static native boolean initCacheMapFiles(String filePath);
|
||||
|
||||
protected static native boolean closeBinaryMapFile(String filePath);
|
||||
|
||||
protected static native void initRenderingRulesStorage(RenderingRulesStorage storage);
|
||||
|
||||
protected static native RenderingGenerationResult generateRenderingIndirect(RenderingContext rc, long searchResultHandler,
|
||||
boolean isTransparent, RenderingRuleSearchRequest render, boolean encodePng);
|
||||
|
||||
protected static native long searchNativeObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom,
|
||||
RenderingRuleSearchRequest request, boolean skipDuplicates, int renderRouteDataFile, Object objectWithInterruptedField,
|
||||
String msgIfNothingFound);
|
||||
|
||||
public static native void testRoutingPing();
|
||||
|
||||
public static native int testNativeRouting(String obfPath, double sLat, double sLon, double eLat, double eLon);
|
||||
|
||||
/**/
|
||||
// Empty native impl
|
||||
/*
|
||||
* protected static NativeRouteSearchResult loadRoutingData(RouteRegion reg, String regName, int regfp,RouteSubregion subreg, boolean
|
||||
* loadObjects) { return null;}
|
||||
*
|
||||
* protected static void deleteRouteSearchResult(long searchResultHandle) {}
|
||||
*
|
||||
* protected static RouteDataObject[] getRouteDataObjects(RouteRegion reg, long rs, int x31, int y31){return null;}
|
||||
*
|
||||
* protected static RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig, float
|
||||
* initDirection, RouteRegion[] regions, RouteCalculationProgress progress) {return null;}
|
||||
*
|
||||
* protected static void deleteSearchResult(long searchResultHandle) {}
|
||||
*
|
||||
* protected static boolean initBinaryMapFile(String filePath) {return false;}
|
||||
*
|
||||
* protected static boolean initCacheMapFiles(String filePath) {return false;}
|
||||
*
|
||||
* protected static boolean closeBinaryMapFile(String filePath) {return false;}
|
||||
*
|
||||
* protected static void initRenderingRulesStorage(RenderingRulesStorage storage) {}
|
||||
*
|
||||
*
|
||||
* protected static RenderingGenerationResult generateRenderingIndirect(RenderingContext rc, long searchResultHandler, boolean
|
||||
* isTransparent, RenderingRuleSearchRequest render, boolean encodePng) { return null; }
|
||||
*
|
||||
* protected static long searchNativeObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom,
|
||||
* RenderingRuleSearchRequest request, boolean skipDuplicates, int renderRouteDataFile, Object objectWithInterruptedField, String
|
||||
* msgIfNothingFound) { return 0; }
|
||||
*
|
||||
* public static void testRoutingPing() {}
|
||||
*
|
||||
* public static int testNativeRouting(String obfPath, double sLat, double sLon, double eLat, double eLon) {return 0;} /*
|
||||
*/
|
||||
|
||||
private static final Log log = PlatformUtil.getLog(NativeLibrary.class);
|
||||
public static boolean loadAllLibs(String path) {
|
||||
boolean b = true;
|
||||
b &= load("Qt5Core", path);
|
||||
b &= load("OsmAndCore", path);
|
||||
b &= load("OsmAndCoreUtils", path);
|
||||
b &= load("OsmAndJNI", path);
|
||||
return b;
|
||||
}
|
||||
|
||||
public static boolean load(String libBaseName, String path) {
|
||||
// look for a pre-installed library
|
||||
if (path != null) {
|
||||
try {
|
||||
System.load(path + libBaseName);
|
||||
return true;
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
log.error(e);
|
||||
} // fall through
|
||||
}
|
||||
|
||||
// guess what a bundled library would be called
|
||||
String osname = System.getProperty("os.name").toLowerCase();
|
||||
String osarch = System.getProperty("os.arch");
|
||||
if (osname.startsWith("mac os")) {
|
||||
osname = "mac";
|
||||
osarch = "universal";
|
||||
}
|
||||
if (osname.startsWith("windows"))
|
||||
osname = "win";
|
||||
if (osname.startsWith("sunos"))
|
||||
osname = "solaris";
|
||||
if (osarch.startsWith("i") && osarch.endsWith("86"))
|
||||
osarch = "x86";
|
||||
String libname = libBaseName + "-" + osname + '-' + osarch + ".lib";
|
||||
|
||||
// try a bundled library
|
||||
try {
|
||||
ClassLoader cl = NativeLibrary.class.getClassLoader();
|
||||
InputStream in = cl.getResourceAsStream( libname);
|
||||
if (in == null) {
|
||||
log.error("libname: " + libname + " not found");
|
||||
return false;
|
||||
}
|
||||
File tmplib = File.createTempFile(libBaseName + "-", ".lib");
|
||||
tmplib.deleteOnExit();
|
||||
OutputStream out = new FileOutputStream(tmplib);
|
||||
byte[] buf = new byte[1024];
|
||||
for (int len; (len = in.read(buf)) != -1;)
|
||||
out.write(buf, 0, len);
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
System.load(tmplib.getAbsolutePath());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage(), e);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} // fall through
|
||||
return false;
|
||||
}
|
||||
}
|
88
OsmAnd-java/src/net/osmand/PlatformUtil.java
Normal file
88
OsmAnd-java/src/net/osmand/PlatformUtil.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package net.osmand;
|
||||
|
||||
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
/**
|
||||
* That class is replacing of standard LogFactory due to
|
||||
* problems with Android implementation of LogFactory.
|
||||
* See Android analog of LogUtil
|
||||
*
|
||||
* That class should be very simple & always use LogFactory methods,
|
||||
* there is an intention to delegate all static methods to LogFactory.
|
||||
*/
|
||||
public class PlatformUtil {
|
||||
|
||||
public static boolean AVIAN_LIBRARY = false;
|
||||
|
||||
public static Log getLog(Class<?> cl){
|
||||
return LogFactory.getLog(cl);
|
||||
}
|
||||
|
||||
public static XmlPullParser newXMLPullParser() throws XmlPullParserException{
|
||||
return new org.kxml2.io.KXmlParser();
|
||||
}
|
||||
|
||||
|
||||
// AVIAN missing dependency
|
||||
/*public static net.osmand.Collator primaryCollator(){
|
||||
return new net.osmand.Collator() {
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
return compare(o1+"", o2+"");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(String source, String target) {
|
||||
if(source == null) {
|
||||
return source == target;
|
||||
}
|
||||
return source.equals(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String source, String target) {
|
||||
if(source == null) {
|
||||
return source == target ? 0 : -1;
|
||||
}
|
||||
return source.compareTo(target);
|
||||
}
|
||||
};
|
||||
}*/
|
||||
|
||||
public static net.osmand.Collator primaryCollator(){
|
||||
final java.text.Collator instance = java.text.Collator.getInstance();
|
||||
instance.setStrength(java.text.Collator.PRIMARY);
|
||||
return wrapCollator(instance);
|
||||
}
|
||||
|
||||
public static net.osmand.Collator wrapCollator(final java.text.Collator instance) {
|
||||
return new net.osmand.Collator() {
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
return instance.compare(o1, o2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return instance.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(String source, String target) {
|
||||
return instance.equals(source, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String source, String target) {
|
||||
return instance.compare(source, target);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
69
OsmAnd-java/src/net/osmand/RenderingContext.java
Normal file
69
OsmAnd-java/src/net/osmand/RenderingContext.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
package net.osmand;
|
||||
|
||||
|
||||
public class RenderingContext {
|
||||
static enum ShadowRenderingMode {
|
||||
// int shadowRenderingMode = 0; // no shadow (minumum CPU)
|
||||
// int shadowRenderingMode = 1; // classic shadow (the implementaton in master)
|
||||
// int shadowRenderingMode = 2; // blur shadow (most CPU, but still reasonable)
|
||||
// int shadowRenderingMode = 3; solid border (CPU use like classic version or even smaller)
|
||||
NO_SHADOW(0), ONE_STEP(1), BLUR_SHADOW(2), SOLID_SHADOW(3);
|
||||
public final int value;
|
||||
|
||||
ShadowRenderingMode(int v) {
|
||||
this.value = v;
|
||||
}
|
||||
}
|
||||
|
||||
// FIELDS OF THAT CLASS ARE USED IN C++
|
||||
public boolean interrupted = false;
|
||||
public boolean nightMode = false;
|
||||
public boolean useEnglishNames = false;
|
||||
public int defaultColor = 0xf1eee8;
|
||||
|
||||
public RenderingContext() {
|
||||
}
|
||||
|
||||
|
||||
public float leftX;
|
||||
public float topY;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public int zoom;
|
||||
public float tileDivisor;
|
||||
public float rotate;
|
||||
|
||||
// debug purpose
|
||||
public int pointCount = 0;
|
||||
public int pointInsideCount = 0;
|
||||
public int visible = 0;
|
||||
public int allObjects = 0;
|
||||
public int textRenderingTime = 0;
|
||||
public int lastRenderedKey = 0;
|
||||
|
||||
// be aware field is using in C++
|
||||
public int shadowRenderingMode = ShadowRenderingMode.BLUR_SHADOW.value;
|
||||
public int shadowRenderingColor = 0xff969696;
|
||||
public String renderingDebugInfo;
|
||||
|
||||
private float density = 1;
|
||||
|
||||
public void setDensityValue(boolean highResMode, float mapTextSize, float density) {
|
||||
// boolean highResMode = false;
|
||||
// float mapTextSize = 1;
|
||||
if (highResMode && density > 1) {
|
||||
this.density = density * mapTextSize;
|
||||
} else {
|
||||
this.density = mapTextSize;
|
||||
}
|
||||
}
|
||||
|
||||
public float getDensityValue(float val) {
|
||||
return val * density;
|
||||
}
|
||||
|
||||
protected byte[] getIconRawData(String data) {
|
||||
return null;
|
||||
}
|
||||
}
|
88
OsmAnd-java/src/net/osmand/Reshaper.java
Normal file
88
OsmAnd-java/src/net/osmand/Reshaper.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package net.osmand;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import com.ibm.icu.text.ArabicShaping;
|
||||
import com.ibm.icu.text.ArabicShapingException;
|
||||
import com.ibm.icu.text.Bidi;
|
||||
import com.ibm.icu.text.BidiRun;
|
||||
|
||||
public class Reshaper {
|
||||
private final static Log LOG = PlatformUtil.getLog(Reshaper.class);
|
||||
|
||||
public static String reshape(String s) {
|
||||
// if(true) {
|
||||
// return s;
|
||||
// }
|
||||
try {
|
||||
ArabicShaping as = new ArabicShaping(ArabicShaping.LETTERS_SHAPE | ArabicShaping.LENGTH_GROW_SHRINK);
|
||||
try {
|
||||
s = as.shape(s);
|
||||
} catch (ArabicShapingException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
Bidi line = new Bidi(s.length(), s.length());
|
||||
line.setPara(s, Bidi.LEVEL_DEFAULT_LTR, null);
|
||||
byte direction = line.getDirection();
|
||||
if (direction != Bidi.MIXED) {
|
||||
// unidirectional
|
||||
if(line.isLeftToRight()) {
|
||||
return s;
|
||||
} else {
|
||||
char[] chs = new char[s.length()];
|
||||
for(int i = 0; i< chs.length ; i++) {
|
||||
chs[i] = s.charAt(chs.length - i - 1);
|
||||
}
|
||||
return new String(chs);
|
||||
}
|
||||
} else {
|
||||
// // mixed-directional
|
||||
int count = line.countRuns();
|
||||
// if (styleRunCount <= 1) {
|
||||
// int style = styleRuns[0].style;
|
||||
// // iterate over directional runs
|
||||
// for (i = 0; i < count; ++i) {
|
||||
// run = line.getVisualRun(i);
|
||||
// renderRun(text, run.getStart(), run.getLimit(),
|
||||
// run.getDirection(), style);
|
||||
// }
|
||||
// }
|
||||
StringBuilder res = new StringBuilder();
|
||||
// iterate over both directional and style runs
|
||||
for (int i = 0; i < count; ++i) {
|
||||
BidiRun run = line.getVisualRun(i);
|
||||
|
||||
int st = run.getStart();
|
||||
int e = run.getLimit();
|
||||
int j = run.getDirection() == Bidi.LTR ? st : e - 1;
|
||||
int l = run.getDirection() == Bidi.LTR ? e : st - 1;
|
||||
boolean plus = run.getDirection() == Bidi.LTR;
|
||||
while (j != l) {
|
||||
res.append(s.charAt(j));
|
||||
if (plus) {
|
||||
j++;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
public static void main(String[] args) {
|
||||
// char[] c = new char[] {'א', 'ד','ם', ' ', '1', '2'} ;
|
||||
// String reshape = "אדם";
|
||||
char[] c = new char[] {'א', 'ד','ם'} ;
|
||||
String reshape = reshape(new String(c));
|
||||
for(int i=0; i < reshape.length(); i++) {
|
||||
System.out.println(reshape.charAt(i));
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
20
OsmAnd-java/src/net/osmand/ResultMatcher.java
Normal file
20
OsmAnd-java/src/net/osmand/ResultMatcher.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* Easy matcher to be able to publish results immediately
|
||||
*
|
||||
*/
|
||||
public interface ResultMatcher<T> {
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return true if result should be added to final list
|
||||
*/
|
||||
boolean publish(T object);
|
||||
|
||||
/**
|
||||
* @returns true to stop processing
|
||||
*/
|
||||
boolean isCancelled();
|
||||
|
||||
}
|
10
OsmAnd-java/src/net/osmand/StateChangedListener.java
Normal file
10
OsmAnd-java/src/net/osmand/StateChangedListener.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* Abstract listener represents state changed for a particular object
|
||||
*/
|
||||
public interface StateChangedListener<T> {
|
||||
|
||||
void stateChanged(T change);
|
||||
|
||||
}
|
17
OsmAnd-java/src/net/osmand/StringMatcher.java
Normal file
17
OsmAnd-java/src/net/osmand/StringMatcher.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package net.osmand;
|
||||
|
||||
/**
|
||||
* Easy matcher to be able to filter streets,buildings, etc.. using custom
|
||||
* rules
|
||||
*
|
||||
* @author pavol.zibrita
|
||||
*/
|
||||
public interface StringMatcher {
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return true if this matcher matches the <code>name</code> String
|
||||
*/
|
||||
boolean matches(String name);
|
||||
|
||||
}
|
32
OsmAnd-java/src/net/osmand/binary/BinaryIndexPart.java
Normal file
32
OsmAnd-java/src/net/osmand/binary/BinaryIndexPart.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
public class BinaryIndexPart {
|
||||
|
||||
String name;
|
||||
int length;
|
||||
int filePointer;
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public int getFilePointer() {
|
||||
return filePointer;
|
||||
}
|
||||
|
||||
public void setFilePointer(int filePointer) {
|
||||
this.filePointer = filePointer;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
667
OsmAnd-java/src/net/osmand/binary/BinaryInspector.java
Normal file
667
OsmAnd-java/src/net/osmand/binary/BinaryInspector.java
Normal file
|
@ -0,0 +1,667 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
|
||||
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.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.osmand.ResultMatcher;
|
||||
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.BinaryMapIndexReader.SearchFilter;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
|
||||
import net.osmand.binary.BinaryMapPoiReaderAdapter.PoiRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapTransportReaderAdapter.TransportIndex;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.data.AmenityType;
|
||||
import net.osmand.data.Building;
|
||||
import net.osmand.data.City;
|
||||
import net.osmand.data.MapObject;
|
||||
import net.osmand.data.Street;
|
||||
import net.osmand.util.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[]{"-vaddress", "-vcities", "-vstreets", "-bbox=14.4,50.1,14.5,50.01", "/home/victor/projects/OsmAnd/data/osm-gen/Map.obf"});
|
||||
// test case extract parts
|
||||
// test case
|
||||
}
|
||||
|
||||
private static void println(String s) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
private static void print(String s) {
|
||||
System.out.print(s);
|
||||
}
|
||||
|
||||
protected static class VerboseInfo {
|
||||
boolean vaddress;
|
||||
boolean vcities;
|
||||
boolean vstreetgroups;
|
||||
boolean vstreets;
|
||||
boolean vbuildings;
|
||||
boolean vintersections;
|
||||
boolean vtransport;
|
||||
boolean vpoi;
|
||||
boolean vmap;
|
||||
boolean vmapObjects;
|
||||
double lattop = 85;
|
||||
double latbottom = -85;
|
||||
double lonleft = -180;
|
||||
double lonright = 180;
|
||||
int zoom = -1;
|
||||
|
||||
public boolean isVaddress() {
|
||||
return vaddress;
|
||||
}
|
||||
|
||||
public int getZoom() {
|
||||
return zoom;
|
||||
}
|
||||
|
||||
public boolean isVmap() {
|
||||
return vmap;
|
||||
}
|
||||
public boolean isVpoi() {
|
||||
return vpoi;
|
||||
}
|
||||
|
||||
public boolean isVtransport() {
|
||||
return vtransport;
|
||||
}
|
||||
|
||||
public VerboseInfo(String[] params){
|
||||
for(int i=0;i<params.length;i++){
|
||||
if(params[i].equals("-vaddress")){
|
||||
vaddress = true;
|
||||
} else if(params[i].equals("-vstreets")){
|
||||
vstreets = true;
|
||||
} else if(params[i].equals("-vstreetgroups")){
|
||||
vstreetgroups = true;
|
||||
} else if(params[i].equals("-vcities")){
|
||||
vcities = true;
|
||||
} else if(params[i].equals("-vbuildings")){
|
||||
vbuildings = true;
|
||||
} else if(params[i].equals("-vintersections")){
|
||||
vintersections = true;
|
||||
} else if(params[i].equals("-vmap")){
|
||||
vmap = true;
|
||||
} else if(params[i].equals("-vmapobjects")){
|
||||
vmapObjects = true;
|
||||
} else if(params[i].equals("-vpoi")){
|
||||
vpoi = true;
|
||||
} else if(params[i].equals("-vtransport")){
|
||||
vtransport = true;
|
||||
} else if(params[i].startsWith("-zoom=")){
|
||||
zoom = Integer.parseInt(params[i].substring("-zoom=".length()));
|
||||
} else if(params[i].startsWith("-bbox=")){
|
||||
String[] values = params[i].substring("-bbox=".length()).split(",");
|
||||
lonleft = Double.parseDouble(values[0]);
|
||||
lattop = Double.parseDouble(values[1]);
|
||||
lonright = Double.parseDouble(values[2]);
|
||||
latbottom = Double.parseDouble(values[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(MapObject o){
|
||||
return lattop >= o.getLocation().getLatitude() && latbottom <= o.getLocation().getLatitude()
|
||||
&& lonleft <= o.getLocation().getLongitude() && lonright >= o.getLocation().getLongitude();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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 HashMap<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) {
|
||||
println("\n" + extracted.size() + " parts were successfully extracted to " + args[1]);
|
||||
}
|
||||
}
|
||||
} else if (f.startsWith("-v")) {
|
||||
if (args.length < 2) {
|
||||
printUsage("Missing file parameter");
|
||||
} else {
|
||||
VerboseInfo vinfo = new VerboseInfo(args);
|
||||
printFileInformation(args[args.length - 1], vinfo);
|
||||
}
|
||||
} else {
|
||||
printUsage("Unknown command : " + f);
|
||||
}
|
||||
} else {
|
||||
printFileInformation(f, null);
|
||||
}
|
||||
}
|
||||
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.getAbsolutePath(), "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(new Float(i + 1f));
|
||||
BinaryIndexPart part = indexes[c].getIndexes().get(i);
|
||||
if(part instanceof MapIndex){
|
||||
List<MapRoot> roots = ((MapIndex) part).getRoots();
|
||||
int rsize = roots.size();
|
||||
for(int j=0; j<rsize; j++){
|
||||
partsSet[c].add(new Float((i+1f)+(j+1)/10f));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pattern != null){
|
||||
minus = pattern.startsWith("-");
|
||||
String[] split = pattern.substring(1).split(",");
|
||||
for(String s : split){
|
||||
temp.add(Float.valueOf(s));
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<Float> p = partsSet[c].iterator();
|
||||
while (p.hasNext()) {
|
||||
Float part = p.next();
|
||||
if (minus) {
|
||||
if (temp.contains(part)) {
|
||||
p.remove();
|
||||
}
|
||||
} else {
|
||||
if (!temp.contains(part)) {
|
||||
p.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
ous.writeInt64(OsmandOdb.OsmAndStructure.DATECREATED_FIELD_NUMBER, System.currentTimeMillis());
|
||||
|
||||
|
||||
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(Float.valueOf(i + 1f))) {
|
||||
continue;
|
||||
}
|
||||
list.add(new Float(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";
|
||||
} 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 if (part instanceof PoiRegion) {
|
||||
ous.writeTag(OsmandOdb.OsmAndStructure.POIINDEX_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
|
||||
map = "POI";
|
||||
} else if (part instanceof RouteRegion) {
|
||||
ous.writeTag(OsmandOdb.OsmAndStructure.ROUTINGINDEX_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
|
||||
map = "Routing";
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
writeInt(ous, part.getLength());
|
||||
copyBinaryPart(ous, BUFFER_TO_READ, raf, part.getFilePointer(), part.getLength());
|
||||
println(MessageFormat.format("{2} part {0} is extracted {1} bytes",
|
||||
new Object[]{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);
|
||||
return formatLatBounds(l, r, t, b);
|
||||
}
|
||||
|
||||
protected static String formatLatBounds(double l, double r, double t, double b){
|
||||
MessageFormat format = new MessageFormat("(left top - right bottom) : {0,number,#.####}, {1,number,#.####} NE - {2,number,#.####}, {3,number,#.####} NE", new Locale("EN", "US"));
|
||||
return format.format(new Object[]{l, t, r, b});
|
||||
}
|
||||
|
||||
public static void printFileInformation(String fileName,VerboseInfo verbose) throws IOException {
|
||||
File file = new File(fileName);
|
||||
if(!file.exists()){
|
||||
println("Binary OsmAnd index " + fileName + " was not found.");
|
||||
return;
|
||||
}
|
||||
printFileInformation(file,verbose);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void printFileInformation(File file, VerboseInfo verbose) throws IOException {
|
||||
RandomAccessFile r = new RandomAccessFile(file.getAbsolutePath(), "r");
|
||||
try {
|
||||
BinaryMapIndexReader index = new BinaryMapIndexReader(r);
|
||||
int i = 1;
|
||||
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 RouteRegion){
|
||||
partname = "Routing";
|
||||
} else if(p instanceof PoiRegion){
|
||||
partname = "Poi";
|
||||
} else if(p instanceof AddressRegion){
|
||||
partname = "Address";
|
||||
}
|
||||
String name = p.getName() == null ? "" : p.getName();
|
||||
println(MessageFormat.format("{0} {1} data {3} - {2,number,#} bytes",
|
||||
new Object[]{Integer.valueOf(i), partname, p.getLength(), name}));
|
||||
if(p instanceof TransportIndex){
|
||||
TransportIndex ti = ((TransportIndex) p);
|
||||
int sh = (31 - BinaryMapIndexReader.TRANSPORT_STOP_ZOOM);
|
||||
println("\tBounds " + formatBounds(ti.getLeft() << sh, ti.getRight() << sh,
|
||||
ti.getTop() << sh, ti.getBottom() << sh));
|
||||
} else if(p instanceof RouteRegion){
|
||||
RouteRegion ri = ((RouteRegion) p);
|
||||
println("\tBounds " + formatLatBounds(ri.getLeftLongitude(), ri.getRightLongitude(),
|
||||
ri.getTopLatitude(), ri.getBottomLatitude()));
|
||||
} else if(p instanceof MapIndex){
|
||||
MapIndex m = ((MapIndex) p);
|
||||
int j = 1;
|
||||
for(MapRoot mi : m.getRoots()){
|
||||
println(MessageFormat.format("\t{4}.{5} Map level minZoom = {0}, maxZoom = {1}, size = {2,number,#} bytes \n\t\tBounds {3}",
|
||||
new Object[] {
|
||||
mi.getMinZoom(), mi.getMaxZoom(), mi.getLength(),
|
||||
formatBounds(mi.getLeft(), mi.getRight(), mi.getTop(), mi.getBottom()),
|
||||
i, j++}));
|
||||
}
|
||||
if((verbose != null && verbose.isVmap())){
|
||||
printMapDetailInfo(verbose, index, m);
|
||||
}
|
||||
} else if(p instanceof PoiRegion && (verbose != null && verbose.isVpoi())){
|
||||
printPOIDetailInfo(verbose, index, (PoiRegion) p);
|
||||
} else if (p instanceof AddressRegion) {
|
||||
List<CitiesBlock> cities = ((AddressRegion) p).cities;
|
||||
for (CitiesBlock c : cities) {
|
||||
println("\t" + i + "." + c.type + " Address part size=" + c.length + " bytes");
|
||||
}
|
||||
if (verbose != null && verbose.isVaddress()) {
|
||||
printAddressDetailedInfo(verbose, index, (AddressRegion) p);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
System.err.println("File is not valid index : " + file.getAbsolutePath());
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void printAddressDetailedInfo(VerboseInfo verbose, BinaryMapIndexReader index, AddressRegion region) throws IOException {
|
||||
String[] cityType_String = new String[] {
|
||||
"Cities/Towns section",
|
||||
"Villages section",
|
||||
"Postcodes section",
|
||||
};
|
||||
int[] cityType = new int[] {
|
||||
BinaryMapAddressReaderAdapter.CITY_TOWN_TYPE,
|
||||
BinaryMapAddressReaderAdapter.VILLAGES_TYPE,
|
||||
BinaryMapAddressReaderAdapter.POSTCODES_TYPE
|
||||
};
|
||||
|
||||
for (int j = 0; j < cityType.length; j++) {
|
||||
int type = cityType[j];
|
||||
final List<City> cities = index.getCities(region, null, type);
|
||||
|
||||
print(MessageFormat.format("\t{0}, {1,number,#} group(s)", new Object[]{cityType_String[j], Integer.valueOf(cities.size())}));
|
||||
if (BinaryMapAddressReaderAdapter.CITY_TOWN_TYPE == type) {
|
||||
if (!verbose.vstreetgroups && !verbose.vcities) {
|
||||
println("");
|
||||
continue;
|
||||
}
|
||||
} else if (!verbose.vstreetgroups) {
|
||||
println("");
|
||||
continue;
|
||||
}
|
||||
println(":");
|
||||
|
||||
for (City c : cities) {
|
||||
int size = index.preloadStreets(c, null);
|
||||
List<Street> streets = new ArrayList<Street>(c.getStreets());
|
||||
print(MessageFormat.format("\t\t''{0}'' [{1,number,#}], {2,number,#} street(s) size {3,number,#} bytes",
|
||||
new Object[]{c.getEnName(), Long.valueOf(c.getId()), Integer.valueOf(streets.size()), Integer.valueOf(size)}));
|
||||
if(!verbose.vstreets)
|
||||
{
|
||||
println("");
|
||||
continue;
|
||||
}
|
||||
println(":");
|
||||
if (!verbose.contains(c))
|
||||
continue;
|
||||
|
||||
for (Street t : streets) {
|
||||
if (!verbose.contains(t))
|
||||
continue;
|
||||
index.preloadBuildings(t, null);
|
||||
final List<Building> buildings = t.getBuildings();
|
||||
final List<Street> intersections = t.getIntersectedStreets();
|
||||
|
||||
println(MessageFormat.format("\t\t\t''{0}'' [{1,number,#}], {2,number,#} building(s), {3,number,#} intersections(s)",
|
||||
new Object[]{t.getEnName(), Long.valueOf(t.getId()), Integer.valueOf(buildings.size()), Integer.valueOf(intersections.size())}));
|
||||
|
||||
if (buildings != null && !buildings.isEmpty() && verbose.vbuildings) {
|
||||
println("\t\t\t\tBuildings:");
|
||||
for (Building b : buildings) {
|
||||
println(MessageFormat.format("\t\t\t\t{0} [{1,number,#}]",
|
||||
new Object[]{b.getName(true), Long.valueOf(b.getId())}));
|
||||
}
|
||||
}
|
||||
|
||||
if (intersections != null && !intersections.isEmpty() && verbose.vintersections) {
|
||||
print("\t\t\t\tIntersects with:");
|
||||
for (Street s : intersections) {
|
||||
println("\t\t\t\t\t" + s.getEnName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static class DamnCounter
|
||||
{
|
||||
int value;
|
||||
}
|
||||
private static void printMapDetailInfo(final VerboseInfo verbose, BinaryMapIndexReader index, MapIndex mapIndex) throws IOException {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
final DamnCounter mapObjectsCounter = new DamnCounter();
|
||||
SearchRequest<BinaryMapDataObject> req = BinaryMapIndexReader.buildSearchRequest(
|
||||
MapUtils.get31TileNumberX(verbose.lonleft),
|
||||
MapUtils.get31TileNumberX(verbose.lonright),
|
||||
MapUtils.get31TileNumberY(verbose.lattop),
|
||||
MapUtils.get31TileNumberY(verbose.latbottom),
|
||||
verbose.getZoom(),
|
||||
new SearchFilter() {
|
||||
@Override
|
||||
public boolean accept(TIntArrayList types, MapIndex index) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ResultMatcher<BinaryMapDataObject>() {
|
||||
@Override
|
||||
public boolean publish(BinaryMapDataObject obj) {
|
||||
mapObjectsCounter.value++;
|
||||
if(verbose.vmapObjects)
|
||||
{
|
||||
b.setLength(0);
|
||||
boolean multipolygon = obj.getPolygonInnerCoordinates() != null && obj.getPolygonInnerCoordinates().length > 0;
|
||||
if(multipolygon ) {
|
||||
b.append("Multipolygon");
|
||||
} else {
|
||||
b.append(obj.area? "Area" : (obj.getPointsLength() > 1? "Way" : "Point"));
|
||||
}
|
||||
int[] types = obj.getTypes();
|
||||
b.append(" types [");
|
||||
for(int j = 0; j<types.length; j++){
|
||||
if(j > 0) {
|
||||
b.append(", ");
|
||||
}
|
||||
TagValuePair pair = obj.getMapIndex().decodeType(types[j]);
|
||||
if(pair == null) {
|
||||
System.err.println("Type " + types[j] + "was not found");
|
||||
continue;
|
||||
// throw new NullPointerException("Type " + obj.getAdditionalTypes()[j] + "was not found");
|
||||
}
|
||||
b.append(pair.toSimpleString()+" ("+types[j]+")");
|
||||
}
|
||||
b.append("]");
|
||||
if(obj.getAdditionalTypes() != null && obj.getAdditionalTypes().length > 0){
|
||||
b.append(" add_types [");
|
||||
for(int j = 0; j<obj.getAdditionalTypes().length; j++){
|
||||
if(j > 0) {
|
||||
b.append(", ");
|
||||
}
|
||||
TagValuePair pair = obj.getMapIndex().decodeType(obj.getAdditionalTypes()[j]);
|
||||
if(pair == null) {
|
||||
System.err.println("Type " + obj.getAdditionalTypes()[j] + "was not found");
|
||||
continue;
|
||||
// throw new NullPointerException("Type " + obj.getAdditionalTypes()[j] + "was not found");
|
||||
}
|
||||
b.append(pair.toSimpleString()+"("+obj.getAdditionalTypes()[j]+")");
|
||||
|
||||
}
|
||||
b.append("]");
|
||||
}
|
||||
TIntObjectHashMap<String> names = obj.getObjectNames();
|
||||
if(names != null && !names.isEmpty()) {
|
||||
b.append(" Names [");
|
||||
int[] keys = names.keys();
|
||||
for(int j = 0; j<keys.length; j++){
|
||||
if(j > 0) {
|
||||
b.append(", ");
|
||||
}
|
||||
TagValuePair pair = obj.getMapIndex().decodeType(keys[j]);
|
||||
if(pair == null) {
|
||||
throw new NullPointerException("Type " + keys[j] + "was not found");
|
||||
}
|
||||
b.append(pair.toSimpleString()+"("+keys[j]+")");
|
||||
b.append(" - ").append(names.get(keys[j]));
|
||||
}
|
||||
b.append("]");
|
||||
}
|
||||
|
||||
b.append(" id ").append((obj.getId() >> 1));
|
||||
b.append(" lat/lon : ");
|
||||
for(int i=0; i<obj.getPointsLength(); i++) {
|
||||
float x = (float) MapUtils.get31LongitudeX(obj.getPoint31XTile(i));
|
||||
float y = (float) MapUtils.get31LatitudeY(obj.getPoint31YTile(i));
|
||||
b.append(x).append(" / ").append(y).append(" , ");
|
||||
}
|
||||
println(b.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
index.searchMapIndex(req, mapIndex);
|
||||
println("\tTotal map objects: " + mapObjectsCounter.value);
|
||||
}
|
||||
|
||||
private static void printPOIDetailInfo(VerboseInfo verbose, BinaryMapIndexReader index, PoiRegion p) throws IOException {
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
MapUtils.get31TileNumberX(verbose.lonleft),
|
||||
MapUtils.get31TileNumberX(verbose.lonright),
|
||||
MapUtils.get31TileNumberY(verbose.lattop),
|
||||
MapUtils.get31TileNumberY(verbose.latbottom),
|
||||
verbose.getZoom(),
|
||||
new SearchPoiTypeFilter() {
|
||||
@Override
|
||||
public boolean accept(AmenityType type, String subcategory) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new ResultMatcher<Amenity>() {
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
println(object.getType().toString() + " : " + object.getSubType() + " " + object.getEnName() + " " + object.getLocation() + " id=" + (object.getId() >> 1));
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
index.initCategories(p);
|
||||
println("\tRegion: " + p.name);
|
||||
println("\t\tBounds " + formatLatBounds(p.getLeftLongitude(), p.getRightLongitude(),
|
||||
p.getTopLatitude(), p.getBottomLatitude()));
|
||||
println("\t\tCategories:");
|
||||
for(int i =0; i< p.categories.size(); i++) {
|
||||
println("\t\t\t" + p.categories.get(i));
|
||||
for(int j = 0; j < p.subcategories.get(i).size(); j++)
|
||||
println("\t\t\t\t" + p.subcategories.get(i).get(j));
|
||||
}
|
||||
req.poiTypeFilter = null;//TODO: for test only
|
||||
index.searchPoi(p, req);
|
||||
|
||||
}
|
||||
|
||||
public static void printUsage(String warning) {
|
||||
if(warning != null){
|
||||
println(warning);
|
||||
}
|
||||
println("Inspector is console utility for working with binary indexes of OsmAnd.");
|
||||
println("It allows print info about file, extract parts and merge indexes.");
|
||||
println("\nUsage for print info : inspector [-vaddress] [-vstreetgroups] [-vstreets] [-vbuildings] [-vintersections] [-vmap] [-vpoi] [-vtransport] [-zoom=Zoom] [-bbox=LeftLon,TopLat,RightLon,BottomLan] [file]");
|
||||
println(" Prints information about [file] binary index of OsmAnd.");
|
||||
println(" -v.. more verbouse output (like all cities and their streets or all map objects with tags/values and coordinates)");
|
||||
println("\nUsage for combining indexes : inspector -c file_to_create (file_from_extract ((+|-)parts_to_extract)? )*");
|
||||
println("\tCreate new file of extracted parts from input file. [parts_to_extract] could be parts to include or exclude.");
|
||||
println(" Example : inspector -c output_file input_file +1,2,3\n\tExtracts 1, 2, 3 parts (could be find in print info)");
|
||||
println(" Example : inspector -c output_file input_file -2,3\n\tExtracts all parts excluding 2, 3");
|
||||
println(" Example : inspector -c output_file input_file1 input_file2 input_file3\n\tSimply combine 3 files");
|
||||
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");
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
52
OsmAnd-java/src/net/osmand/binary/BinaryInspectorNative.java
Normal file
52
OsmAnd-java/src/net/osmand/binary/BinaryInspectorNative.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.osmand.NativeLibrary;
|
||||
import net.osmand.bridge.ObfInspector;
|
||||
import net.osmand.bridge.StringVector;
|
||||
|
||||
public class BinaryInspectorNative {
|
||||
|
||||
|
||||
public static final int BUFFER_SIZE = 1 << 20;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
if(args == null || args.length == 0) {
|
||||
printUsage(null);
|
||||
return;
|
||||
}
|
||||
args = new String[]{"-vmap", "-bbox=11.3,47.1,11.6,47", "/home/victor/projects/OsmAnd/data/osm-gen/Austria_2.obf"};
|
||||
// test cases show info
|
||||
NativeLibrary.loadAllLibs(null);
|
||||
StringVector vector = new StringVector();
|
||||
for(int i = 0; i < args.length; i++) {
|
||||
vector.add(args[i]);
|
||||
}
|
||||
ObfInspector.inspector(vector);
|
||||
}
|
||||
|
||||
public static void printUsage(String warning) {
|
||||
if(warning != null){
|
||||
println(warning);
|
||||
}
|
||||
println("Inspector is console utility for working with binary indexes of OsmAnd.");
|
||||
println("It allows print info about file, extract parts and merge indexes.");
|
||||
println("\nUsage for print info : inspector [-vaddress] [-vstreetgroups] [-vstreets] [-vbuildings] [-vintersections] [-vmap] [-vpoi] [-vtransport] [-zoom=Zoom] [-bbox=LeftLon,TopLat,RightLon,BottomLan] [file]");
|
||||
println(" Prints information about [file] binary index of OsmAnd.");
|
||||
println(" -v.. more verbouse output (like all cities and their streets or all map objects with tags/values and coordinates)");
|
||||
println("\nUsage for combining indexes : inspector -c file_to_create (file_from_extract ((+|-)parts_to_extract)? )*");
|
||||
println("\tCreate new file of extracted parts from input file. [parts_to_extract] could be parts to include or exclude.");
|
||||
println(" Example : inspector -c output_file input_file +1,2,3\n\tExtracts 1, 2, 3 parts (could be find in print info)");
|
||||
println(" Example : inspector -c output_file input_file -2,3\n\tExtracts all parts excluding 2, 3");
|
||||
println(" Example : inspector -c output_file input_file1 input_file2 input_file3\n\tSimply combine 3 files");
|
||||
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");
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static void println(String string) {
|
||||
System.out.println(string);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,593 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.CollatorStringMatcher;
|
||||
import net.osmand.CollatorStringMatcher.StringMatcherMode;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.StringMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.OsmandOdb.AddressNameIndexDataAtom;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndAddressIndex.CitiesIndex;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndAddressNameIndexData;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndAddressNameIndexData.AddressNameIndexData;
|
||||
import net.osmand.data.Building;
|
||||
import net.osmand.data.Building.BuildingInterpolation;
|
||||
import net.osmand.data.City;
|
||||
import net.osmand.data.City.CityType;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.MapObject;
|
||||
import net.osmand.data.Street;
|
||||
import net.osmand.util.MapUtils;
|
||||
import net.sf.junidecode.Junidecode;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.WireFormat;
|
||||
|
||||
public class BinaryMapAddressReaderAdapter {
|
||||
|
||||
public final static int CITY_TOWN_TYPE = 1;
|
||||
public final static int POSTCODES_TYPE = 2;
|
||||
public final static int VILLAGES_TYPE = 3;
|
||||
public final static int STREET_TYPE = 4;
|
||||
|
||||
private static final Log LOG = PlatformUtil.getLog(BinaryMapAddressReaderAdapter.class);
|
||||
|
||||
public static class AddressRegion extends BinaryIndexPart {
|
||||
String enName;
|
||||
int indexNameOffset = -1;
|
||||
List<CitiesBlock> cities = new ArrayList<BinaryMapAddressReaderAdapter.CitiesBlock>();
|
||||
|
||||
LatLon calculatedCenter = null;
|
||||
|
||||
public String getEnName() {
|
||||
return enName;
|
||||
}
|
||||
|
||||
public List<CitiesBlock> getCities() {
|
||||
return cities;
|
||||
}
|
||||
|
||||
public int getIndexNameOffset() {
|
||||
return indexNameOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CitiesBlock extends BinaryIndexPart {
|
||||
int type;
|
||||
}
|
||||
|
||||
private CodedInputStream codedIS;
|
||||
private final BinaryMapIndexReader map;
|
||||
|
||||
protected BinaryMapAddressReaderAdapter(BinaryMapIndexReader map){
|
||||
this.codedIS = map.codedIS;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
private void skipUnknownField(int t) throws IOException {
|
||||
map.skipUnknownField(t);
|
||||
}
|
||||
|
||||
private int readInt() throws IOException {
|
||||
return map.readInt();
|
||||
}
|
||||
|
||||
|
||||
protected void readAddressIndex(AddressRegion region) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
if(region.enName == null || region.enName.length() == 0){
|
||||
region.enName = Junidecode.unidecode(region.name);
|
||||
}
|
||||
return;
|
||||
case OsmandOdb.OsmAndAddressIndex.NAME_FIELD_NUMBER :
|
||||
region.name = codedIS.readString();
|
||||
break;
|
||||
case OsmandOdb.OsmAndAddressIndex.NAME_EN_FIELD_NUMBER :
|
||||
region.enName = codedIS.readString();
|
||||
break;
|
||||
case OsmandOdb.OsmAndAddressIndex.CITIES_FIELD_NUMBER :
|
||||
CitiesBlock block = new CitiesBlock();
|
||||
region.cities.add(block);
|
||||
block.type = 1;
|
||||
block.length = readInt();
|
||||
block.filePointer = codedIS.getTotalBytesRead();
|
||||
while(true){
|
||||
int tt = codedIS.readTag();
|
||||
int ttag = WireFormat.getTagFieldNumber(tt);
|
||||
if(ttag == 0) {
|
||||
break;
|
||||
} else if(ttag == CitiesIndex.TYPE_FIELD_NUMBER){
|
||||
block.type = codedIS.readUInt32();
|
||||
break;
|
||||
} else {
|
||||
skipUnknownField(tt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
codedIS.seek(block.filePointer + block.length);
|
||||
|
||||
break;
|
||||
case OsmandOdb.OsmAndAddressIndex.NAMEINDEX_FIELD_NUMBER :
|
||||
region.indexNameOffset = codedIS.getTotalBytesRead();
|
||||
int length = readInt();
|
||||
codedIS.seek(region.indexNameOffset + length + 4);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void readCities(List<City> cities, SearchRequest<City> resultMatcher, StringMatcher matcher, boolean useEn) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case CitiesIndex.CITIES_FIELD_NUMBER :
|
||||
int fp = codedIS.getTotalBytesRead();
|
||||
int length = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
City c = readCityHeader(matcher, fp, useEn);
|
||||
if(c != null){
|
||||
if (resultMatcher == null || resultMatcher.publish(c)) {
|
||||
cities.add(c);
|
||||
}
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
if(resultMatcher != null && resultMatcher.isCancelled()){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void readCityStreets(SearchRequest<Street> resultMatcher, City city) throws IOException{
|
||||
int x = MapUtils.get31TileNumberX(city.getLocation().getLongitude());
|
||||
int y = MapUtils.get31TileNumberY(city.getLocation().getLatitude());
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.CityBlockIndex.STREETS_FIELD_NUMBER :
|
||||
Street s = new Street(city);
|
||||
s.setFileOffset(codedIS.getTotalBytesRead());
|
||||
int length = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
readStreet(s, null, false, x >> 7, y >> 7, city.isPostcode() ? city.getName() : null);
|
||||
if(resultMatcher == null || resultMatcher.publish(s)){
|
||||
city.registerStreet(s);
|
||||
}
|
||||
if(resultMatcher != null && resultMatcher.isCancelled()) {
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmandOdb.CityBlockIndex.BUILDINGS_FIELD_NUMBER :
|
||||
// buildings for the town are not used now
|
||||
skipUnknownField(t);
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected City readCityHeader(StringMatcher nameMatcher, int filePointer, boolean useEn) throws IOException{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
City c = null;
|
||||
boolean englishNameMatched = false;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return c;
|
||||
case OsmandOdb.CityIndex.CITY_TYPE_FIELD_NUMBER :
|
||||
int type = codedIS.readUInt32();
|
||||
c = new City(CityType.values()[type]);
|
||||
break;
|
||||
case OsmandOdb.CityIndex.ID_FIELD_NUMBER :
|
||||
c.setId(codedIS.readUInt64());
|
||||
if(nameMatcher != null && useEn && !englishNameMatched){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.CityIndex.NAME_EN_FIELD_NUMBER :
|
||||
String enName = codedIS.readString();
|
||||
if (nameMatcher != null && enName.length() > 0 && nameMatcher.matches(enName)) {
|
||||
englishNameMatched = true;
|
||||
}
|
||||
c.setEnName(enName);
|
||||
break;
|
||||
case OsmandOdb.CityIndex.NAME_FIELD_NUMBER :
|
||||
String name = codedIS.readString();
|
||||
if(nameMatcher != null){
|
||||
if(!useEn){
|
||||
if(!nameMatcher.matches(name)) {
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return null;
|
||||
}
|
||||
} else if(nameMatcher.matches(Junidecode.unidecode(name))){
|
||||
englishNameMatched = true;
|
||||
}
|
||||
}
|
||||
if(c == null) {
|
||||
c = City.createPostcode(name);
|
||||
}
|
||||
c.setName(name);
|
||||
break;
|
||||
case OsmandOdb.CityIndex.X_FIELD_NUMBER :
|
||||
x = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.CityIndex.Y_FIELD_NUMBER :
|
||||
y = codedIS.readUInt32();
|
||||
c.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x));
|
||||
if(c.getEnName().length() == 0){
|
||||
c.setEnName(Junidecode.unidecode(c.getName()));
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.CityIndex.SHIFTTOCITYBLOCKINDEX_FIELD_NUMBER :
|
||||
int offset = readInt();
|
||||
offset += filePointer;
|
||||
c.setFileOffset(offset);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Street readStreet(Street s, SearchRequest<Building> buildingsMatcher, boolean loadBuildingsAndIntersected, int city24X, int city24Y, String postcodeFilter) throws IOException{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
boolean loadLocation = city24X != 0 || city24Y != 0;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
if(loadLocation){
|
||||
s.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x));
|
||||
}
|
||||
if(s.getEnName().length() == 0){
|
||||
s.setEnName(Junidecode.unidecode(s.getName()));
|
||||
}
|
||||
return s;
|
||||
case OsmandOdb.StreetIndex.ID_FIELD_NUMBER :
|
||||
s.setId(codedIS.readUInt64());
|
||||
break;
|
||||
case OsmandOdb.StreetIndex.NAME_EN_FIELD_NUMBER :
|
||||
s.setEnName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.StreetIndex.NAME_FIELD_NUMBER :
|
||||
s.setName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.StreetIndex.X_FIELD_NUMBER :
|
||||
int sx = codedIS.readSInt32();
|
||||
if(loadLocation){
|
||||
x = sx + city24X;
|
||||
} else {
|
||||
x = (int) MapUtils.getTileNumberX(24, s.getLocation().getLongitude());
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.StreetIndex.Y_FIELD_NUMBER :
|
||||
int sy = codedIS.readSInt32();
|
||||
if(loadLocation){
|
||||
y = sy + city24Y;
|
||||
} else {
|
||||
y = (int) MapUtils.getTileNumberY(24, s.getLocation().getLatitude());
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.StreetIndex.INTERSECTIONS_FIELD_NUMBER :
|
||||
int length = codedIS.readRawVarint32();
|
||||
if(loadBuildingsAndIntersected){
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
Street si = readIntersectedStreet(s.getCity(), x, y);
|
||||
s.addIntersectedStreet(si);
|
||||
codedIS.popLimit(oldLimit);
|
||||
} else {
|
||||
codedIS.skipRawBytes(length);
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.StreetIndex.BUILDINGS_FIELD_NUMBER :
|
||||
int offset = codedIS.getTotalBytesRead();
|
||||
length = codedIS.readRawVarint32();
|
||||
if(loadBuildingsAndIntersected){
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
Building b = readBuilding(offset, x, y);
|
||||
if (postcodeFilter == null || postcodeFilter.equalsIgnoreCase(b.getPostcode())) {
|
||||
if (buildingsMatcher == null || buildingsMatcher.publish(b)) {
|
||||
s.addBuilding(b);
|
||||
}
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
} else {
|
||||
codedIS.skipRawBytes(length);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Street readIntersectedStreet(City c, int street24X, int street24Y) throws IOException{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
Street s = new Street(c);
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
s.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x));
|
||||
if(s.getEnName().length() == 0){
|
||||
s.setEnName(Junidecode.unidecode(s.getName()));
|
||||
}
|
||||
return s;
|
||||
case OsmandOdb.BuildingIndex.ID_FIELD_NUMBER :
|
||||
s.setId(codedIS.readUInt64());
|
||||
break;
|
||||
case OsmandOdb.StreetIntersection.NAME_EN_FIELD_NUMBER:
|
||||
s.setEnName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.StreetIntersection.NAME_FIELD_NUMBER:
|
||||
s.setName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.StreetIntersection.INTERSECTEDX_FIELD_NUMBER :
|
||||
x = codedIS.readSInt32() + street24X;
|
||||
break;
|
||||
case OsmandOdb.StreetIntersection.INTERSECTEDY_FIELD_NUMBER :
|
||||
y = codedIS.readSInt32() + street24Y;
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Building readBuilding(int fileOffset, int street24X, int street24Y) throws IOException{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int x2 = 0;
|
||||
int y2 = 0;
|
||||
Building b = new Building();
|
||||
b.setFileOffset(fileOffset);
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
b.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x));
|
||||
if(x2 != 0 && y2 != 0) {
|
||||
b.setLatLon2(new LatLon(MapUtils.getLatitudeFromTile(24, y2), MapUtils.getLongitudeFromTile(24, x2)));
|
||||
}
|
||||
if(b.getEnName().length() == 0){
|
||||
b.setEnName(Junidecode.unidecode(b.getName()));
|
||||
}
|
||||
return b;
|
||||
case OsmandOdb.BuildingIndex.ID_FIELD_NUMBER :
|
||||
b.setId(codedIS.readUInt64());
|
||||
break;
|
||||
|
||||
case OsmandOdb.BuildingIndex.NAME_EN_FIELD_NUMBER :
|
||||
b.setEnName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.NAME_FIELD_NUMBER :
|
||||
b.setName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.NAME_EN2_FIELD_NUMBER :
|
||||
// no where to set now
|
||||
codedIS.readString();
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.NAME2_FIELD_NUMBER :
|
||||
b.setName2(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.INTERPOLATION_FIELD_NUMBER :
|
||||
int sint = codedIS.readSInt32();
|
||||
if(sint > 0) {
|
||||
b.setInterpolationInterval(sint);
|
||||
} else {
|
||||
b.setInterpolationType(BuildingInterpolation.fromValue(sint));
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.X_FIELD_NUMBER :
|
||||
x = codedIS.readSInt32() + street24X;
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.X2_FIELD_NUMBER :
|
||||
x2 = codedIS.readSInt32() + street24X;
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.Y_FIELD_NUMBER :
|
||||
y = codedIS.readSInt32() + street24Y;
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.Y2_FIELD_NUMBER :
|
||||
y2 = codedIS.readSInt32() + street24Y;
|
||||
break;
|
||||
case OsmandOdb.BuildingIndex.POSTCODE_FIELD_NUMBER :
|
||||
b.setPostcode(codedIS.readString());
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void searchAddressDataByName(AddressRegion reg, SearchRequest<MapObject> req, int[] typeFilter) throws IOException {
|
||||
TIntArrayList loffsets = new TIntArrayList();
|
||||
CollatorStringMatcher matcher = new CollatorStringMatcher( req.nameQuery, StringMatcherMode.CHECK_STARTS_FROM_SPACE);
|
||||
long time = System.currentTimeMillis();
|
||||
int indexOffset = 0;
|
||||
while (true) {
|
||||
if (req.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmAndAddressNameIndexData.TABLE_FIELD_NUMBER:
|
||||
int length = readInt();
|
||||
indexOffset = codedIS.getTotalBytesRead();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
// here offsets are sorted by distance
|
||||
map.readIndexedStringTable(matcher.getCollator(), req.nameQuery, "", loffsets, 0);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmAndAddressNameIndexData.ATOM_FIELD_NUMBER:
|
||||
// also offsets can be randomly skipped by limit
|
||||
loffsets.sort();
|
||||
TIntArrayList[] refs = new TIntArrayList[5];
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
refs[i] = new TIntArrayList();
|
||||
}
|
||||
|
||||
LOG.info("Searched address structure in " + (System.currentTimeMillis() - time) + "ms. Found " + loffsets.size()
|
||||
+ " subtress");
|
||||
for (int j = 0; j < loffsets.size(); j++) {
|
||||
int fp = indexOffset + loffsets.get(j);
|
||||
codedIS.seek(fp);
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
int stag = 0;
|
||||
do {
|
||||
int st = codedIS.readTag();
|
||||
stag = WireFormat.getTagFieldNumber(st);
|
||||
if(stag == AddressNameIndexData.ATOM_FIELD_NUMBER) {
|
||||
int slen = codedIS.readRawVarint32();
|
||||
int soldLim = codedIS.pushLimit(slen);
|
||||
readAddressNameData(req, refs, fp);
|
||||
codedIS.popLimit(soldLim);
|
||||
} else if(stag != 0){
|
||||
skipUnknownField(st);
|
||||
}
|
||||
} while(stag != 0);
|
||||
|
||||
codedIS.popLimit(oldLim);
|
||||
if (req.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (typeFilter == null) {
|
||||
typeFilter = new int[] { CITY_TOWN_TYPE, POSTCODES_TYPE, VILLAGES_TYPE, STREET_TYPE };
|
||||
}
|
||||
for (int i = 0; i < typeFilter.length && !req.isCancelled(); i++) {
|
||||
TIntArrayList list = refs[typeFilter[i]];
|
||||
if (typeFilter[i] == STREET_TYPE) {
|
||||
for (int j = 0; j < list.size() && !req.isCancelled(); j += 2) {
|
||||
City obj = null;
|
||||
{
|
||||
codedIS.seek(list.get(j + 1));
|
||||
int len = codedIS.readRawVarint32();
|
||||
int old = codedIS.pushLimit(len);
|
||||
obj = readCityHeader(null, list.get(j + 1), false);
|
||||
codedIS.popLimit(old);
|
||||
}
|
||||
if (obj != null) {
|
||||
codedIS.seek(list.get(j));
|
||||
int len = codedIS.readRawVarint32();
|
||||
int old = codedIS.pushLimit(len);
|
||||
LatLon l = obj.getLocation();
|
||||
Street s = new Street(obj);
|
||||
readStreet(s, null, false, MapUtils.get31TileNumberX(l.getLongitude()) >> 7,
|
||||
MapUtils.get31TileNumberY(l.getLatitude()) >> 7, obj.isPostcode() ? obj.getName() : null);
|
||||
|
||||
if (matcher.matches(s.getName())) {
|
||||
req.publish(s);
|
||||
}
|
||||
codedIS.popLimit(old);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
list.sort();
|
||||
for (int j = 0; j < list.size() && !req.isCancelled(); j++) {
|
||||
codedIS.seek(list.get(j));
|
||||
int len = codedIS.readRawVarint32();
|
||||
int old = codedIS.pushLimit(len);
|
||||
City obj = readCityHeader(matcher, list.get(j), false);
|
||||
if (obj != null) {
|
||||
req.publish(obj);
|
||||
}
|
||||
codedIS.popLimit(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.info("Whole address search by name is done in " + (System.currentTimeMillis() - time) + "ms. Found "
|
||||
+ req.getSearchResults().size());
|
||||
return;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void readAddressNameData(SearchRequest<MapObject> req, TIntArrayList[] refs, int fp) throws IOException {
|
||||
TIntArrayList toAdd = null;
|
||||
while(true){
|
||||
if(req.isCancelled()){
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case AddressNameIndexDataAtom.NAMEEN_FIELD_NUMBER :
|
||||
codedIS.readString();
|
||||
break;
|
||||
case AddressNameIndexDataAtom.NAME_FIELD_NUMBER :
|
||||
codedIS.readString();
|
||||
break;
|
||||
case AddressNameIndexDataAtom.SHIFTTOCITYINDEX_FIELD_NUMBER :
|
||||
if(toAdd != null) {
|
||||
toAdd.add(fp - codedIS.readInt32());
|
||||
}
|
||||
break;
|
||||
case AddressNameIndexDataAtom.SHIFTTOINDEX_FIELD_NUMBER :
|
||||
if(toAdd != null) {
|
||||
toAdd.add(fp - codedIS.readInt32());
|
||||
}
|
||||
break;
|
||||
case AddressNameIndexDataAtom.TYPE_FIELD_NUMBER :
|
||||
int type = codedIS.readInt32();
|
||||
toAdd = refs[type];
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
166
OsmAnd-java/src/net/osmand/binary/BinaryMapDataObject.java
Normal file
166
OsmAnd-java/src/net/osmand/binary/BinaryMapDataObject.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
|
||||
import net.osmand.render.RenderingRulesStorage;
|
||||
|
||||
public class BinaryMapDataObject {
|
||||
protected int[] coordinates = null;
|
||||
protected int[][] polygonInnerCoordinates = null;
|
||||
protected boolean area = false;
|
||||
protected int[] types = null;
|
||||
protected int[] additionalTypes = null;
|
||||
protected int objectType = RenderingRulesStorage.POINT_RULES;
|
||||
|
||||
protected TIntObjectHashMap<String> objectNames = null;
|
||||
protected long id = 0;
|
||||
|
||||
protected MapIndex mapIndex = null;
|
||||
|
||||
|
||||
public BinaryMapDataObject(){
|
||||
}
|
||||
|
||||
public BinaryMapDataObject(int[] coordinates, int[] types, int[][] polygonInnerCoordinates, long id){
|
||||
this.polygonInnerCoordinates = polygonInnerCoordinates;
|
||||
this.coordinates = coordinates;
|
||||
this.additionalTypes = new int[0];
|
||||
this.types = types;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
protected void setCoordinates(int[] coordinates) {
|
||||
this.coordinates = coordinates;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
if(objectNames == null){
|
||||
return "";
|
||||
}
|
||||
String name = objectNames.get(mapIndex.nameEncodingType);
|
||||
if(name == null){
|
||||
return "";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public TIntObjectHashMap<String> getObjectNames() {
|
||||
return objectNames;
|
||||
}
|
||||
|
||||
public void putObjectName(int type, String name){
|
||||
if(objectNames == null){
|
||||
objectNames = new TIntObjectHashMap<String>();
|
||||
}
|
||||
objectNames.put(type, name);
|
||||
}
|
||||
|
||||
public int[][] getPolygonInnerCoordinates() {
|
||||
return polygonInnerCoordinates;
|
||||
}
|
||||
|
||||
public int[] getTypes(){
|
||||
return types;
|
||||
}
|
||||
|
||||
public boolean containsType(int cachedType) {
|
||||
if(cachedType != -1) {
|
||||
for(int i=0; i<types.length; i++){
|
||||
if(types[i] == cachedType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsAdditionalType(int cachedType) {
|
||||
if (cachedType != -1) {
|
||||
for (int i = 0; i < additionalTypes.length; i++) {
|
||||
if (additionalTypes[i] == cachedType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getNameByType(int type) {
|
||||
if(type != -1 && objectNames != null) {
|
||||
return objectNames.get(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] getAdditionalTypes() {
|
||||
return additionalTypes;
|
||||
}
|
||||
|
||||
public boolean isArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
public boolean isCycle(){
|
||||
if(coordinates == null || coordinates.length < 2) {
|
||||
return false;
|
||||
}
|
||||
return coordinates[0] == coordinates[coordinates.length - 2] &&
|
||||
coordinates[1] == coordinates[coordinates.length - 1];
|
||||
}
|
||||
|
||||
public void setArea(boolean area) {
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
protected void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
protected void setTypes(int[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
|
||||
public int getSimpleLayer(){
|
||||
if(mapIndex != null) {
|
||||
for (int i = 0; i < additionalTypes.length; i++) {
|
||||
if (mapIndex.positiveLayers.contains(additionalTypes[i])) {
|
||||
return 1;
|
||||
} else if (mapIndex.negativeLayers.contains(additionalTypes[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public MapIndex getMapIndex() {
|
||||
return mapIndex;
|
||||
}
|
||||
|
||||
public void setMapIndex(MapIndex mapIndex) {
|
||||
this.mapIndex = mapIndex;
|
||||
}
|
||||
|
||||
public int getPointsLength(){
|
||||
if(coordinates == null){
|
||||
return 0;
|
||||
}
|
||||
return coordinates.length / 2;
|
||||
}
|
||||
public int getPoint31YTile(int ind) {
|
||||
return coordinates[2 * ind + 1];
|
||||
}
|
||||
|
||||
public int getPoint31XTile(int ind) {
|
||||
return coordinates[2 * ind];
|
||||
}
|
||||
|
||||
|
||||
}
|
171
OsmAnd-java/src/net/osmand/binary/BinaryMapIndexFilter.java
Normal file
171
OsmAnd-java/src/net/osmand/binary/BinaryMapIndexFilter.java
Normal file
|
@ -0,0 +1,171 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.set.hash.TIntHashSet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader.MapIndex;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchFilter;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
|
||||
import net.osmand.render.RenderingRulesStorage;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class BinaryMapIndexFilter {
|
||||
|
||||
private final BinaryMapIndexReader reader;
|
||||
|
||||
public BinaryMapIndexFilter(File file) throws IOException{
|
||||
reader = new BinaryMapIndexReader(new RandomAccessFile(file.getPath(), "r"));
|
||||
}
|
||||
|
||||
|
||||
private static class Stat {
|
||||
int pointCount = 0;
|
||||
int totalCount = 0;
|
||||
int wayCount = 0;
|
||||
int polygonCount = 0;
|
||||
int polygonBigSize = 0;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return " ways " + wayCount + " polygons " + polygonCount + " points " + pointCount + " total " + totalCount +"\n"+
|
||||
" polygons big size " + polygonBigSize;
|
||||
}
|
||||
}
|
||||
|
||||
private double calculateArea(BinaryMapDataObject o, int zoom){
|
||||
double sum = 0;
|
||||
for(int i=0; i< o.getPointsLength(); i++){
|
||||
double x = MapUtils.getTileNumberX(zoom + 8, MapUtils.get31LongitudeX(o.getPoint31XTile(i)));
|
||||
int prev = i == 0 ? o.getPointsLength() - 1 : i -1;
|
||||
int next = i == o.getPointsLength() - 1 ? 0 : i + 1;
|
||||
double y1 = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(prev)));
|
||||
double y2 = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(next)));
|
||||
sum += x * (y1 - y2);
|
||||
}
|
||||
return Math.abs(sum);
|
||||
}
|
||||
|
||||
private double calculateLength(BinaryMapDataObject o, int zoom){
|
||||
double sum = 0;
|
||||
for(int i=1; i< o.getPointsLength(); i++){
|
||||
double x = MapUtils.getTileNumberX(zoom + 8, MapUtils.get31LongitudeX(o.getPoint31XTile(i)));
|
||||
double y = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(i)));
|
||||
double x2 = MapUtils.getTileNumberX(zoom + 8, MapUtils.get31LongitudeX(o.getPoint31XTile(i - 1)));
|
||||
double y2 = MapUtils.getTileNumberY(zoom + 8, MapUtils.get31LatitudeY(o.getPoint31YTile(i - 1)));
|
||||
sum += Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
|
||||
}
|
||||
return Math.abs(sum);
|
||||
}
|
||||
|
||||
private int tilesCovers(BinaryMapDataObject o, int zoom, TIntHashSet set){
|
||||
set.clear();
|
||||
for(int i=0; i< o.getPointsLength(); i++){
|
||||
int x = (int) MapUtils.getTileNumberX(zoom, MapUtils.get31LongitudeX(o.getPoint31XTile(i)));
|
||||
int y = (int) MapUtils.getTileNumberY(zoom, MapUtils.get31LatitudeY(o.getPoint31YTile(i)));
|
||||
int val = ((x << 16) | y);
|
||||
set.add(val);
|
||||
}
|
||||
return set.size();
|
||||
}
|
||||
|
||||
private Stat process(final int zoom) throws IOException {
|
||||
final Stat stat = new Stat();
|
||||
final Map<TagValuePair, Integer> map = new HashMap<TagValuePair, Integer>();
|
||||
SearchFilter sf = new SearchFilter() {
|
||||
@Override
|
||||
public boolean accept(TIntArrayList types, MapIndex index) {
|
||||
boolean polygon = false;
|
||||
boolean polyline = false;
|
||||
for (int j = 0; j < types.size(); j++) {
|
||||
int wholeType = types.get(j);
|
||||
TagValuePair pair = index.decodeType(wholeType);
|
||||
if (pair != null) {
|
||||
int t = wholeType & 3;
|
||||
if (t == RenderingRulesStorage.POINT_RULES) {
|
||||
stat.pointCount++;
|
||||
} else if (t == RenderingRulesStorage.LINE_RULES) {
|
||||
stat.wayCount++;
|
||||
polyline = true;
|
||||
} else {
|
||||
polygon = true;
|
||||
stat.polygonCount++;
|
||||
if (!map.containsKey(pair)) {
|
||||
map.put(pair, 0);
|
||||
}
|
||||
map.put(pair, map.get(pair) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
stat.totalCount++;
|
||||
return polyline;
|
||||
}
|
||||
};
|
||||
ResultMatcher<BinaryMapDataObject> matcher = new ResultMatcher<BinaryMapDataObject>() {
|
||||
TIntHashSet set = new TIntHashSet();
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean publish(BinaryMapDataObject object) {
|
||||
// double area = calculateArea(object, zoom);
|
||||
double len = calculateLength(object, zoom);
|
||||
if(/*tilesCovers(object, zoom, set) >= 2 && */ len > 100){
|
||||
stat.polygonBigSize ++;
|
||||
if(stat.polygonBigSize % 10000 == 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
SearchRequest<BinaryMapDataObject> req = BinaryMapIndexReader.buildSearchRequest(0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, zoom,
|
||||
sf, matcher);
|
||||
List<BinaryMapDataObject> result = reader.searchMapIndex(req);
|
||||
|
||||
ArrayList<TagValuePair> list = new ArrayList<TagValuePair>(map.keySet());
|
||||
Collections.sort(list, new Comparator<TagValuePair>() {
|
||||
@Override
|
||||
public int compare(TagValuePair o1, TagValuePair o2) {
|
||||
return -map.get(o1) + map.get(o2);
|
||||
}
|
||||
|
||||
});
|
||||
for(TagValuePair tp : list){
|
||||
Integer i = map.get(tp);
|
||||
if(i > 10){
|
||||
// System.out.println(tp.toString() + " " + i);
|
||||
}
|
||||
}
|
||||
|
||||
for(BinaryMapDataObject obj : result){
|
||||
System.out.println("id " + (obj.getId() >> 3) + " " + calculateArea(obj, zoom));
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] iargs) throws IOException {
|
||||
BinaryMapIndexFilter filter = new BinaryMapIndexFilter(new File(""));
|
||||
for (int i = 10; i <= 14; i++) {
|
||||
Stat st = filter.process(i);
|
||||
System.out.println(i + " zoom -> " + st);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
2109
OsmAnd-java/src/net/osmand/binary/BinaryMapIndexReader.java
Normal file
2109
OsmAnd-java/src/net/osmand/binary/BinaryMapIndexReader.java
Normal file
File diff suppressed because it is too large
Load diff
718
OsmAnd-java/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java
Normal file
718
OsmAnd-java/src/net/osmand/binary/BinaryMapPoiReaderAdapter.java
Normal file
|
@ -0,0 +1,718 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.hash.TIntLongHashMap;
|
||||
import gnu.trove.set.hash.TLongHashSet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.Collator;
|
||||
import net.osmand.CollatorStringMatcher;
|
||||
import net.osmand.CollatorStringMatcher.StringMatcherMode;
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndPoiNameIndex.OsmAndPoiNameIndexData;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.data.AmenityType;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
import net.sf.junidecode.Junidecode;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.WireFormat;
|
||||
|
||||
public class BinaryMapPoiReaderAdapter {
|
||||
private static final Log LOG = PlatformUtil.getLog(BinaryMapPoiReaderAdapter.class);
|
||||
|
||||
public static final int SHIFT_BITS_CATEGORY = 7;
|
||||
private static final int CATEGORY_MASK = (1 << SHIFT_BITS_CATEGORY) - 1 ;
|
||||
private static final int ZOOM_TO_SKIP_FILTER = 3;
|
||||
private static final int BUCKET_SEARCH_BY_NAME = 5;
|
||||
|
||||
public static class PoiRegion extends BinaryIndexPart {
|
||||
|
||||
List<String> categories = new ArrayList<String>();
|
||||
List<AmenityType> categoriesType = new ArrayList<AmenityType>();
|
||||
List<List<String> > subcategories = new ArrayList<List<String> >();
|
||||
|
||||
double leftLongitude;
|
||||
double rightLongitude;
|
||||
double topLatitude;
|
||||
double bottomLatitude;
|
||||
|
||||
public double getLeftLongitude() {
|
||||
return leftLongitude;
|
||||
}
|
||||
|
||||
public double getRightLongitude() {
|
||||
return rightLongitude;
|
||||
}
|
||||
|
||||
public double getTopLatitude() {
|
||||
return topLatitude;
|
||||
}
|
||||
|
||||
public double getBottomLatitude() {
|
||||
return bottomLatitude;
|
||||
}
|
||||
}
|
||||
|
||||
private CodedInputStream codedIS;
|
||||
private final BinaryMapIndexReader map;
|
||||
|
||||
protected BinaryMapPoiReaderAdapter(BinaryMapIndexReader map){
|
||||
this.codedIS = map.codedIS;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
private void skipUnknownField(int t) throws IOException {
|
||||
map.skipUnknownField(t);
|
||||
}
|
||||
|
||||
private int readInt() throws IOException {
|
||||
return map.readInt();
|
||||
}
|
||||
|
||||
private void readPoiBoundariesIndex(PoiRegion region) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndTileBox.LEFT_FIELD_NUMBER:
|
||||
region.leftLongitude = MapUtils.get31LongitudeX(codedIS.readUInt32());
|
||||
break;
|
||||
case OsmandOdb.OsmAndTileBox.RIGHT_FIELD_NUMBER:
|
||||
region.rightLongitude = MapUtils.get31LongitudeX(codedIS.readUInt32());
|
||||
break;
|
||||
case OsmandOdb.OsmAndTileBox.TOP_FIELD_NUMBER:
|
||||
region.topLatitude = MapUtils.get31LatitudeY(codedIS.readUInt32());
|
||||
break;
|
||||
case OsmandOdb.OsmAndTileBox.BOTTOM_FIELD_NUMBER:
|
||||
region.bottomLatitude = MapUtils.get31LatitudeY(codedIS.readUInt32());
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void readPoiIndex(PoiRegion region, boolean readCategories) throws IOException {
|
||||
int length;
|
||||
int oldLimit;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndPoiIndex.NAME_FIELD_NUMBER :
|
||||
region.name = codedIS.readString();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiIndex.BOUNDARIES_FIELD_NUMBER:
|
||||
length = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
readPoiBoundariesIndex(region);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiIndex.CATEGORIESTABLE_FIELD_NUMBER :
|
||||
if(!readCategories){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return;
|
||||
}
|
||||
length = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
readCategory(region);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER :
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readCategory(PoiRegion region) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndCategoryTable.CATEGORY_FIELD_NUMBER :
|
||||
String cat = codedIS.readString().intern();
|
||||
region.categories.add(cat);
|
||||
region.categoriesType.add(AmenityType.fromString(cat));
|
||||
region.subcategories.add(new ArrayList<String>());
|
||||
break;
|
||||
case OsmandOdb.OsmAndCategoryTable.SUBCATEGORIES_FIELD_NUMBER :
|
||||
region.subcategories.get(region.subcategories.size() - 1).add(codedIS.readString().intern());
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initCategories(PoiRegion region) throws IOException {
|
||||
if(region.categories.isEmpty()) {
|
||||
codedIS.seek(region.filePointer);
|
||||
int oldLimit = codedIS.pushLimit(region.length);
|
||||
readPoiIndex(region, true);
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
}
|
||||
|
||||
protected void searchPoiByName( PoiRegion region, SearchRequest<Amenity> req) throws IOException {
|
||||
TIntLongHashMap offsets = new TIntLongHashMap();
|
||||
CollatorStringMatcher matcher = new CollatorStringMatcher(req.nameQuery,
|
||||
StringMatcherMode.CHECK_STARTS_FROM_SPACE);
|
||||
long time = System.currentTimeMillis();
|
||||
int indexOffset = codedIS.getTotalBytesRead();
|
||||
while(true){
|
||||
if(req.isCancelled()){
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndPoiIndex.NAMEINDEX_FIELD_NUMBER :
|
||||
int length = readInt();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
// here offsets are sorted by distance
|
||||
offsets = readPoiNameIndex(matcher.getCollator(), req.nameQuery, req);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER :
|
||||
// also offsets can be randomly skipped by limit
|
||||
Integer[] offKeys = new Integer[offsets.size()];
|
||||
if (offsets.size() > 0) {
|
||||
int[] keys = offsets.keys();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
offKeys[i] = keys[i];
|
||||
}
|
||||
final TIntLongHashMap foffsets = offsets;
|
||||
Arrays.sort(offKeys, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer object1, Integer object2) {
|
||||
return Double.compare(foffsets.get(object1), foffsets.get(object2));
|
||||
}
|
||||
});
|
||||
int p = BUCKET_SEARCH_BY_NAME * 3 ;
|
||||
if (p < offKeys.length) {
|
||||
for (int i = p + BUCKET_SEARCH_BY_NAME;; i += BUCKET_SEARCH_BY_NAME) {
|
||||
if (i > offKeys.length) {
|
||||
Arrays.sort(offKeys, p, offKeys.length);
|
||||
break;
|
||||
} else {
|
||||
Arrays.sort(offKeys, p, i);
|
||||
}
|
||||
p = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LOG.info("Searched poi structure in "+(System.currentTimeMillis() - time) +
|
||||
"ms. Found " + offKeys.length +" subtress");
|
||||
for (int j = 0; j < offKeys.length; j++) {
|
||||
codedIS.seek(offKeys[j] + indexOffset);
|
||||
int len = readInt();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
readPoiData(matcher, req, region);
|
||||
codedIS.popLimit(oldLim);
|
||||
if(req.isCancelled() || req.limitExceeded()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG.info("Whole poi by name search is done in "+(System.currentTimeMillis() - time) +
|
||||
"ms. Found " + req.getSearchResults().size());
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TIntLongHashMap readPoiNameIndex(Collator instance, String query, SearchRequest<Amenity> req) throws IOException {
|
||||
TIntLongHashMap offsets = new TIntLongHashMap();
|
||||
TIntArrayList dataOffsets = null;
|
||||
int offset = 0;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return offsets;
|
||||
case OsmandOdb.OsmAndPoiNameIndex.TABLE_FIELD_NUMBER : {
|
||||
int length = readInt();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
dataOffsets = new TIntArrayList();
|
||||
offset = codedIS.getTotalBytesRead();
|
||||
map.readIndexedStringTable(instance, query, "", dataOffsets, 0);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break; }
|
||||
case OsmandOdb.OsmAndPoiNameIndex.DATA_FIELD_NUMBER : {
|
||||
if(dataOffsets != null){
|
||||
dataOffsets.sort(); // 1104125
|
||||
for (int i = 0; i < dataOffsets.size(); i++) {
|
||||
codedIS.seek(dataOffsets.get(i) + offset);
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
readPoiNameIndexData(offsets, req);
|
||||
codedIS.popLimit(oldLim);
|
||||
if (req.isCancelled()) {
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return offsets;
|
||||
}
|
||||
}
|
||||
}
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return offsets; }
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void readPoiNameIndexData(TIntLongHashMap offsets, SearchRequest<Amenity> req) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmAndPoiNameIndexData.ATOMS_FIELD_NUMBER :
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
readPoiNameIndexDataAtom(offsets, req);
|
||||
codedIS.popLimit(oldLim);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void readPoiNameIndexDataAtom(TIntLongHashMap offsets, SearchRequest<Amenity> req) throws IOException {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int zoom = 15;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndPoiNameIndexDataAtom.X_FIELD_NUMBER :
|
||||
x = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiNameIndexDataAtom.Y_FIELD_NUMBER :
|
||||
y = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiNameIndexDataAtom.ZOOM_FIELD_NUMBER :
|
||||
zoom = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiNameIndexDataAtom.SHIFTTO_FIELD_NUMBER :
|
||||
int x31 = (x << (31 - zoom));
|
||||
int y31 = (y << (31 - zoom));
|
||||
int shift = readInt();
|
||||
if (req.contains(x31, y31, x31, y31)) {
|
||||
long d = Math.abs(req.x - x31) + Math.abs(req.y - y31);
|
||||
offsets.put(shift, d);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void searchPoiIndex(int left31, int right31, int top31, int bottom31,
|
||||
SearchRequest<Amenity> req, PoiRegion region) throws IOException {
|
||||
int indexOffset = codedIS.getTotalBytesRead();
|
||||
long time = System.currentTimeMillis();
|
||||
TLongHashSet skipTiles = null;
|
||||
int zoomToSkip = 31;
|
||||
if(req.zoom != -1){
|
||||
skipTiles = new TLongHashSet();
|
||||
zoomToSkip = req.zoom + ZOOM_TO_SKIP_FILTER;
|
||||
}
|
||||
int length ;
|
||||
int oldLimit ;
|
||||
TIntLongHashMap offsetsMap = new TIntLongHashMap();
|
||||
while(true){
|
||||
if(req.isCancelled()){
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER :
|
||||
length = readInt();
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsetsMap, skipTiles, req, region);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER :
|
||||
int[] offsets = offsetsMap.keys();
|
||||
// also offsets can be randomly skipped by limit
|
||||
Arrays.sort(offsets);
|
||||
if(skipTiles != null){
|
||||
skipTiles.clear();
|
||||
}
|
||||
LOG.info("Searched poi structure in "+(System.currentTimeMillis() - time) +
|
||||
"ms. Found " + offsets.length +" subtress");
|
||||
for (int j = 0; j < offsets.length; j++) {
|
||||
codedIS.seek(offsets[j] + indexOffset);
|
||||
int len = readInt();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
readPoiData(left31, right31, top31, bottom31, req, region, skipTiles, zoomToSkip);
|
||||
codedIS.popLimit(oldLim);
|
||||
if(req.isCancelled()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readPoiData(CollatorStringMatcher matcher, SearchRequest<Amenity> req, PoiRegion region) throws IOException {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int zoom = 0;
|
||||
while(true){
|
||||
if(req.isCancelled() || req.limitExceeded()){
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndPoiBoxData.X_FIELD_NUMBER :
|
||||
x = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxData.ZOOM_FIELD_NUMBER :
|
||||
zoom = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxData.Y_FIELD_NUMBER :
|
||||
y = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxData.POIDATA_FIELD_NUMBER:
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
Amenity am = readPoiPoint(0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, x, y, zoom, req, region, false);
|
||||
codedIS.popLimit(oldLim);
|
||||
if (am != null) {
|
||||
if(matcher.matches(am.getName(false)) || matcher.matches(am.getName(true))) {
|
||||
req.publish(am);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readPoiData(int left31, int right31, int top31, int bottom31,
|
||||
SearchRequest<Amenity> req, PoiRegion region, TLongHashSet toSkip, int zSkip) throws IOException {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int zoom = 0;
|
||||
while(true){
|
||||
if(req.isCancelled()){
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndPoiBoxData.X_FIELD_NUMBER :
|
||||
x = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxData.ZOOM_FIELD_NUMBER :
|
||||
zoom = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxData.Y_FIELD_NUMBER :
|
||||
y = codedIS.readUInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxData.POIDATA_FIELD_NUMBER:
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLim = codedIS.pushLimit(len);
|
||||
Amenity am = readPoiPoint(left31, right31, top31, bottom31, x, y, zoom, req, region, true);
|
||||
codedIS.popLimit(oldLim);
|
||||
if (am != null) {
|
||||
if (toSkip != null) {
|
||||
int xp = (int) MapUtils.getTileNumberX(zSkip, am.getLocation().getLongitude());
|
||||
int yp = (int) MapUtils.getTileNumberY(zSkip, am.getLocation().getLatitude());
|
||||
long val = (((long) xp) << zSkip) | yp;
|
||||
if (!toSkip.contains(val)) {
|
||||
boolean publish = req.publish(am);
|
||||
if(publish) {
|
||||
toSkip.add(val);
|
||||
}
|
||||
}
|
||||
if(zSkip <= zoom){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
req.publish(am);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Amenity readPoiPoint(int left31, int right31, int top31, int bottom31,
|
||||
int px, int py, int zoom, SearchRequest<Amenity> req, PoiRegion region, boolean checkBounds) throws IOException {
|
||||
Amenity am = null;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
AmenityType amenityType = null;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
if(amenityType == null && (tag > OsmandOdb.OsmAndPoiBoxDataAtom.CATEGORIES_FIELD_NUMBER || tag == 0)) {
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return null;
|
||||
}
|
||||
switch (tag) {
|
||||
case 0:
|
||||
if(Algorithms.isEmpty(am.getEnName())){
|
||||
am.setEnName(Junidecode.unidecode(am.getName()));
|
||||
}
|
||||
req.numberOfAcceptedObjects++;
|
||||
return am;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.DX_FIELD_NUMBER :
|
||||
x = (codedIS.readSInt32() + (px << (24 - zoom))) << 7;
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.DY_FIELD_NUMBER :
|
||||
y = (codedIS.readSInt32() + (py << (24 - zoom))) << 7;
|
||||
req.numberOfVisitedObjects++;
|
||||
if (checkBounds) {
|
||||
if (left31 > x || right31 < x || top31 > y || bottom31 < y) {
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
am = new Amenity();
|
||||
am.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x));
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.CATEGORIES_FIELD_NUMBER :
|
||||
int cat = codedIS.readUInt32();
|
||||
int subcatId = cat >> SHIFT_BITS_CATEGORY;
|
||||
int catId = cat & CATEGORY_MASK;
|
||||
AmenityType type = AmenityType.OTHER;
|
||||
String subtype = "";
|
||||
if (catId < region.categoriesType.size()) {
|
||||
type = region.categoriesType.get(catId);
|
||||
List<String> subcats = region.subcategories.get(catId);
|
||||
if (subcatId < subcats.size()) {
|
||||
subtype = subcats.get(subcatId);
|
||||
}
|
||||
}
|
||||
if (req.poiTypeFilter == null || req.poiTypeFilter.accept(type, subtype)) {
|
||||
if (amenityType == null) {
|
||||
amenityType = type;
|
||||
am.setSubType(subtype);
|
||||
am.setType(amenityType);
|
||||
} else {
|
||||
am.setSubType(am.getSubType() + ";" + subtype);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.ID_FIELD_NUMBER :
|
||||
am.setId(codedIS.readUInt64());
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.NAME_FIELD_NUMBER :
|
||||
am.setName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.NAMEEN_FIELD_NUMBER :
|
||||
am.setEnName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.OPENINGHOURS_FIELD_NUMBER :
|
||||
am.setOpeningHours(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.SITE_FIELD_NUMBER :
|
||||
am.setSite(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.PHONE_FIELD_NUMBER:
|
||||
am.setPhone(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBoxDataAtom.NOTE_FIELD_NUMBER:
|
||||
am.setDescription(codedIS.readString());
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkCategories(SearchRequest<Amenity> req, PoiRegion region) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return false;
|
||||
case OsmandOdb.OsmAndPoiCategories.CATEGORIES_FIELD_NUMBER:
|
||||
AmenityType type = AmenityType.OTHER;
|
||||
String subcat = "";
|
||||
int cat = codedIS.readUInt32();
|
||||
int subcatId = cat >> SHIFT_BITS_CATEGORY;
|
||||
int catId = cat & CATEGORY_MASK;
|
||||
if(catId < region.categoriesType.size()){
|
||||
type = region.categoriesType.get(catId);
|
||||
List<String> subcats = region.subcategories.get(catId);
|
||||
if(subcatId < subcats.size()){
|
||||
subcat = subcats.get(subcatId);
|
||||
}
|
||||
} else {
|
||||
type = AmenityType.OTHER;
|
||||
}
|
||||
if(req.poiTypeFilter.accept(type, subcat)){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readBoxField(int left31, int right31, int top31, int bottom31,
|
||||
int px, int py, int pzoom, TIntLongHashMap offsetsMap, TLongHashSet skipTiles, SearchRequest<Amenity> req, PoiRegion region) throws IOException {
|
||||
req.numberOfReadSubtrees++;
|
||||
int zoomToSkip = req.zoom + ZOOM_TO_SKIP_FILTER;
|
||||
boolean checkBox = true;
|
||||
boolean existsCategories = false;
|
||||
int zoom = pzoom;
|
||||
int dy = py;
|
||||
int dx = px;
|
||||
while(true){
|
||||
if(req.isCancelled()){
|
||||
return false;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return existsCategories;
|
||||
case OsmandOdb.OsmAndPoiBox.ZOOM_FIELD_NUMBER :
|
||||
zoom = codedIS.readUInt32() + pzoom;
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBox.LEFT_FIELD_NUMBER :
|
||||
dx = codedIS.readSInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBox.TOP_FIELD_NUMBER:
|
||||
dy = codedIS.readSInt32();
|
||||
break;
|
||||
case OsmandOdb.OsmAndPoiBox.CATEGORIES_FIELD_NUMBER:
|
||||
if(req.poiTypeFilter == null){
|
||||
skipUnknownField(t);
|
||||
} else {
|
||||
int length = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
boolean check = checkCategories(req, region);
|
||||
codedIS.popLimit(oldLimit);
|
||||
if(!check){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return false;
|
||||
}
|
||||
existsCategories = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER: {
|
||||
int x = dx + (px << (zoom - pzoom));
|
||||
int y = dy + (py << (zoom - pzoom));
|
||||
if(checkBox){
|
||||
int xL = x << (31 - zoom);
|
||||
int xR = ((x + 1) << (31 - zoom)) - 1;
|
||||
int yT = y << (31 - zoom);
|
||||
int yB = ((y + 1) << (31 - zoom)) - 1;
|
||||
// check intersection
|
||||
if(left31 > xR || xL > right31 || bottom31 < yT || yB < top31){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return false;
|
||||
}
|
||||
req.numberOfAcceptedSubtrees++;
|
||||
checkBox = false;
|
||||
}
|
||||
|
||||
int length = readInt();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
boolean exists = readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsetsMap, skipTiles, req, region);
|
||||
codedIS.popLimit(oldLimit);
|
||||
|
||||
if (skipTiles != null && zoom >= zoomToSkip && exists) {
|
||||
long val = ((((long) x) >> (zoom - zoomToSkip)) << zoomToSkip) | (((long) y) >> (zoom - zoomToSkip));
|
||||
if(skipTiles.contains(val)){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case OsmandOdb.OsmAndPoiBox.SHIFTTODATA_FIELD_NUMBER: {
|
||||
int x = dx + (px << (zoom - pzoom));
|
||||
int y = dy + (py << (zoom - pzoom));
|
||||
long l = ((((x << zoom) | y) << 5) | zoom);
|
||||
offsetsMap.put(readInt(), l);
|
||||
if(skipTiles != null && zoom >= zoomToSkip){
|
||||
long val = ((((long) x) >> (zoom - zoomToSkip)) << zoomToSkip) | (((long) y) >> (zoom - zoomToSkip));
|
||||
skipTiles.add(val);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,927 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
import gnu.trove.iterator.TLongObjectIterator;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.list.array.TLongArrayList;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.binary.OsmandOdb.IdTable;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteBorderBox;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteBorderLine;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteBorderLine.Builder;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteBorderPoint;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteBorderPointsBlock;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteDataBlock;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteDataBox;
|
||||
import net.osmand.binary.OsmandOdb.OsmAndRoutingIndex.RouteEncodingRule;
|
||||
import net.osmand.binary.OsmandOdb.RestrictionData;
|
||||
import net.osmand.binary.OsmandOdb.RouteData;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.WireFormat;
|
||||
|
||||
public class BinaryMapRouteReaderAdapter {
|
||||
protected static final Log LOG = PlatformUtil.getLog(BinaryMapRouteReaderAdapter.class);
|
||||
private static final int SHIFT_COORDINATES = 4;
|
||||
|
||||
public static class RouteTypeRule {
|
||||
private final static int ACCESS = 1;
|
||||
private final static int ONEWAY = 2;
|
||||
private final static int HIGHWAY_TYPE = 3;
|
||||
private final static int MAXSPEED = 4;
|
||||
private final static int ROUNDABOUT = 5;
|
||||
public final static int TRAFFIC_SIGNALS = 6;
|
||||
public final static int RAILWAY_CROSSING = 7;
|
||||
private final static int LANES = 8;
|
||||
private final String t;
|
||||
private final String v;
|
||||
private int intValue;
|
||||
private float floatValue;
|
||||
private int type;
|
||||
|
||||
public RouteTypeRule(String t, String v) {
|
||||
this.t = t.intern();
|
||||
if("true".equals(v)) {
|
||||
v = "yes";
|
||||
}
|
||||
if("false".equals(v)) {
|
||||
v = "no";
|
||||
}
|
||||
this.v = v == null? null : v.intern();
|
||||
analyze();
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return t;
|
||||
}
|
||||
|
||||
public String getValue(){
|
||||
return v;
|
||||
}
|
||||
|
||||
public boolean roundabout(){
|
||||
return type == ROUNDABOUT;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int onewayDirection(){
|
||||
if(type == ONEWAY){
|
||||
return intValue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float maxSpeed(){
|
||||
if(type == MAXSPEED){
|
||||
return floatValue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int lanes(){
|
||||
if(type == LANES){
|
||||
return intValue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String highwayRoad(){
|
||||
if(type == HIGHWAY_TYPE){
|
||||
return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void analyze() {
|
||||
if(t.equalsIgnoreCase("oneway")){
|
||||
type = ONEWAY;
|
||||
if("-1".equals(v) || "reverse".equals(v)) {
|
||||
intValue = -1;
|
||||
} else if("1".equals(v) || "yes".equals(v)) {
|
||||
intValue = 1;
|
||||
} else {
|
||||
intValue = 0;
|
||||
}
|
||||
} else if(t.equalsIgnoreCase("highway") && "traffic_signals".equals(v)){
|
||||
type = TRAFFIC_SIGNALS;
|
||||
} else if(t.equalsIgnoreCase("railway") && ("crossing".equals(v) || "level_crossing".equals(v))){
|
||||
type = RAILWAY_CROSSING;
|
||||
} else if(t.equalsIgnoreCase("roundabout") && v != null){
|
||||
type = ROUNDABOUT;
|
||||
} else if(t.equalsIgnoreCase("junction") && "roundabout".equalsIgnoreCase(v)){
|
||||
type = ROUNDABOUT;
|
||||
} else if(t.equalsIgnoreCase("highway") && v != null){
|
||||
type = HIGHWAY_TYPE;
|
||||
} else if(t.startsWith("access") && v != null){
|
||||
type = ACCESS;
|
||||
} else if(t.equalsIgnoreCase("maxspeed") && v != null){
|
||||
type = MAXSPEED;
|
||||
floatValue = -1;
|
||||
if(v.equals("none")) {
|
||||
floatValue = RouteDataObject.NONE_MAX_SPEED;
|
||||
} else {
|
||||
int i = 0;
|
||||
while (i < v.length() && Character.isDigit(v.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
if (i > 0) {
|
||||
floatValue = Integer.parseInt(v.substring(0, i));
|
||||
floatValue /= 3.6; // km/h -> m/s
|
||||
if (v.contains("mph")) {
|
||||
floatValue *= 1.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (t.equalsIgnoreCase("lanes") && v != null) {
|
||||
intValue = -1;
|
||||
int i = 0;
|
||||
type = LANES;
|
||||
while (i < v.length() && Character.isDigit(v.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
if (i > 0) {
|
||||
intValue = Integer.parseInt(v.substring(0, i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static class RouteRegion extends BinaryIndexPart {
|
||||
public int regionsRead;
|
||||
public int borderBoxPointer = 0;
|
||||
public int baseBorderBoxPointer = 0;
|
||||
public int borderBoxLength = 0;
|
||||
public int baseBorderBoxLength = 0;
|
||||
|
||||
List<RouteSubregion> subregions = new ArrayList<RouteSubregion>();
|
||||
List<RouteSubregion> basesubregions = new ArrayList<RouteSubregion>();
|
||||
List<RouteTypeRule> routeEncodingRules = new ArrayList<BinaryMapRouteReaderAdapter.RouteTypeRule>();
|
||||
|
||||
int nameTypeRule = -1;
|
||||
int refTypeRule = -1;
|
||||
int destinationTypeRule = -1;
|
||||
|
||||
public RouteTypeRule quickGetEncodingRule(int id) {
|
||||
return routeEncodingRules.get(id);
|
||||
}
|
||||
|
||||
private void initRouteEncodingRule(int id, String tags, String val) {
|
||||
while(routeEncodingRules.size() <= id) {
|
||||
routeEncodingRules.add(null);
|
||||
}
|
||||
routeEncodingRules.set(id, new RouteTypeRule(tags, val));
|
||||
if(tags.equals("name")) {
|
||||
nameTypeRule = id;
|
||||
} else if(tags.equals("ref")) {
|
||||
refTypeRule = id;
|
||||
} else if(tags.equals("destination")) {
|
||||
destinationTypeRule = id;
|
||||
}
|
||||
}
|
||||
|
||||
public List<RouteSubregion> getSubregions(){
|
||||
return subregions;
|
||||
}
|
||||
|
||||
public List<RouteSubregion> getBaseSubregions(){
|
||||
return basesubregions;
|
||||
}
|
||||
|
||||
public double getLeftLongitude() {
|
||||
double l = 180;
|
||||
for(RouteSubregion s : subregions) {
|
||||
l = Math.min(l, MapUtils.get31LongitudeX(s.left));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public double getRightLongitude() {
|
||||
double l = -180;
|
||||
for(RouteSubregion s : subregions) {
|
||||
l = Math.max(l, MapUtils.get31LongitudeX(s.right));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public double getBottomLatitude() {
|
||||
double l = 90;
|
||||
for(RouteSubregion s : subregions) {
|
||||
l = Math.min(l, MapUtils.get31LatitudeY(s.bottom));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public double getTopLatitude() {
|
||||
double l = -90;
|
||||
for(RouteSubregion s : subregions) {
|
||||
l = Math.max(l, MapUtils.get31LatitudeY(s.top));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
// Used in C++
|
||||
public static class RouteSubregion {
|
||||
private final static int INT_SIZE = 4;
|
||||
public final RouteRegion routeReg;
|
||||
public RouteSubregion(RouteSubregion copy) {
|
||||
this.routeReg = copy.routeReg;
|
||||
this.left = copy.left;
|
||||
this.right = copy.right;
|
||||
this.top = copy.top;
|
||||
this.bottom = copy.bottom;
|
||||
this.filePointer = copy.filePointer;
|
||||
this.length = copy.length;
|
||||
|
||||
}
|
||||
public RouteSubregion(RouteRegion routeReg) {
|
||||
this.routeReg = routeReg;
|
||||
}
|
||||
public int length;
|
||||
public int filePointer;
|
||||
public int left;
|
||||
public int right;
|
||||
public int top;
|
||||
public int bottom;
|
||||
public int shiftToData;
|
||||
public List<RouteSubregion> subregions = null;
|
||||
public List<RouteDataObject> dataObjects = null;
|
||||
|
||||
public int getEstimatedSize(){
|
||||
int shallow = 7 * INT_SIZE + 4*3;
|
||||
if (subregions != null) {
|
||||
shallow += 8;
|
||||
for (RouteSubregion s : subregions) {
|
||||
shallow += s.getEstimatedSize();
|
||||
}
|
||||
}
|
||||
return shallow;
|
||||
}
|
||||
|
||||
public int countSubregions(){
|
||||
int cnt = 1;
|
||||
if (subregions != null) {
|
||||
for (RouteSubregion s : subregions) {
|
||||
cnt += s.countSubregions();
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
private CodedInputStream codedIS;
|
||||
private final BinaryMapIndexReader map;
|
||||
|
||||
protected BinaryMapRouteReaderAdapter(BinaryMapIndexReader map){
|
||||
this.codedIS = map.codedIS;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
private void skipUnknownField(int t) throws IOException {
|
||||
map.skipUnknownField(t);
|
||||
}
|
||||
|
||||
private int readInt() throws IOException {
|
||||
return map.readInt();
|
||||
}
|
||||
|
||||
|
||||
protected void readRouteIndex(RouteRegion region) throws IOException {
|
||||
int routeEncodingRule =1;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndRoutingIndex.NAME_FIELD_NUMBER :
|
||||
region.name = codedIS.readString();
|
||||
break;
|
||||
case OsmandOdb.OsmAndRoutingIndex.RULES_FIELD_NUMBER: {
|
||||
int len = codedIS.readInt32();
|
||||
int oldLimit = codedIS.pushLimit(len);
|
||||
readRouteEncodingRule(region, routeEncodingRule++);
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
codedIS.popLimit(oldLimit);
|
||||
} break;
|
||||
case OsmandOdb.OsmAndRoutingIndex.ROOTBOXES_FIELD_NUMBER :
|
||||
case OsmandOdb.OsmAndRoutingIndex.BASEMAPBOXES_FIELD_NUMBER :{
|
||||
RouteSubregion subregion = new RouteSubregion(region);
|
||||
subregion.length = readInt();
|
||||
subregion.filePointer = codedIS.getTotalBytesRead();
|
||||
int oldLimit = codedIS.pushLimit(subregion.length);
|
||||
readRouteTree(subregion, null, 0, true);
|
||||
if(tag == OsmandOdb.OsmAndRoutingIndex.ROOTBOXES_FIELD_NUMBER) {
|
||||
region.subregions.add(subregion);
|
||||
} else {
|
||||
region.basesubregions.add(subregion);
|
||||
}
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
}
|
||||
case OsmandOdb.OsmAndRoutingIndex.BASEBORDERBOX_FIELD_NUMBER:
|
||||
case OsmandOdb.OsmAndRoutingIndex.BORDERBOX_FIELD_NUMBER: {
|
||||
int length = readInt();
|
||||
int filePointer = codedIS.getTotalBytesRead();
|
||||
if(tag == OsmandOdb.OsmAndRoutingIndex.BORDERBOX_FIELD_NUMBER) {
|
||||
region.borderBoxLength = length;
|
||||
region.borderBoxPointer = filePointer;
|
||||
} else {
|
||||
region.baseBorderBoxLength = length;
|
||||
region.baseBorderBoxPointer = filePointer;
|
||||
}
|
||||
codedIS.skipRawBytes(length);
|
||||
break;
|
||||
}
|
||||
case OsmandOdb.OsmAndRoutingIndex.BLOCKS_FIELD_NUMBER : {
|
||||
// Finish reading file!
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RouteDataObject readRouteDataObject(RouteRegion reg, int pleftx, int ptopy) throws IOException {
|
||||
RouteDataObject o = new RouteDataObject(reg);
|
||||
TIntArrayList pointsX = new TIntArrayList();
|
||||
TIntArrayList pointsY = new TIntArrayList();
|
||||
TIntArrayList types = new TIntArrayList();
|
||||
List<TIntArrayList> globalpointTypes = new ArrayList<TIntArrayList>();
|
||||
while (true) {
|
||||
int ts = codedIS.readTag();
|
||||
int tags = WireFormat.getTagFieldNumber(ts);
|
||||
switch (tags) {
|
||||
case 0:
|
||||
o.pointsX = pointsX.toArray();
|
||||
o.pointsY = pointsY.toArray();
|
||||
o.types = types.toArray();
|
||||
if(globalpointTypes.size() > 0){
|
||||
o.pointTypes = new int[globalpointTypes.size()][];
|
||||
for(int k=0; k<o.pointTypes.length; k++) {
|
||||
TIntArrayList l = globalpointTypes.get(k);
|
||||
if(l != null) {
|
||||
o.pointTypes[k] = l.toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return o;
|
||||
case RouteData.TYPES_FIELD_NUMBER:
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(len);
|
||||
while(codedIS.getBytesUntilLimit() > 0) {
|
||||
types.add(codedIS.readRawVarint32());
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case RouteData.STRINGNAMES_FIELD_NUMBER:
|
||||
o.names = new TIntObjectHashMap<String>();
|
||||
int sizeL = codedIS.readRawVarint32();
|
||||
int old = codedIS.pushLimit(sizeL);
|
||||
while (codedIS.getBytesUntilLimit() > 0) {
|
||||
int stag = codedIS.readRawVarint32();
|
||||
int pId = codedIS.readRawVarint32();
|
||||
o.names.put(stag, ((char)pId)+"");
|
||||
}
|
||||
codedIS.popLimit(old);
|
||||
break;
|
||||
case RouteData.POINTS_FIELD_NUMBER:
|
||||
len = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(len);
|
||||
int px = pleftx >> SHIFT_COORDINATES;
|
||||
int py = ptopy >> SHIFT_COORDINATES;
|
||||
while(codedIS.getBytesUntilLimit() > 0){
|
||||
int x = (codedIS.readSInt32() ) + px;
|
||||
int y = (codedIS.readSInt32() ) + py;
|
||||
pointsX.add(x << SHIFT_COORDINATES);
|
||||
pointsY.add(y << SHIFT_COORDINATES);
|
||||
px = x;
|
||||
py = y;
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case RouteData.POINTTYPES_FIELD_NUMBER:
|
||||
len = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(len);
|
||||
while (codedIS.getBytesUntilLimit() > 0) {
|
||||
int pointInd = codedIS.readRawVarint32();
|
||||
TIntArrayList pointTypes = new TIntArrayList();
|
||||
int lens = codedIS.readRawVarint32();
|
||||
int oldLimits = codedIS.pushLimit(lens);
|
||||
while (codedIS.getBytesUntilLimit() > 0) {
|
||||
pointTypes.add(codedIS.readRawVarint32());
|
||||
}
|
||||
codedIS.popLimit(oldLimits);
|
||||
while (pointInd >= globalpointTypes.size()) {
|
||||
globalpointTypes.add(null);
|
||||
}
|
||||
globalpointTypes.set(pointInd, pointTypes);
|
||||
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case RouteData.ROUTEID_FIELD_NUMBER:
|
||||
o.id = codedIS.readInt32();
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(ts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void readRouteTreeData(RouteSubregion routeTree, TLongArrayList idTables,
|
||||
TLongObjectHashMap<TLongArrayList> restrictions) throws IOException {
|
||||
routeTree.dataObjects = new ArrayList<RouteDataObject>();
|
||||
idTables.clear();
|
||||
restrictions.clear();
|
||||
List<String> stringTable = null;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
TLongObjectIterator<TLongArrayList> it = restrictions.iterator();
|
||||
while (it.hasNext()) {
|
||||
it.advance();
|
||||
int from = (int) it.key();
|
||||
RouteDataObject fromr = routeTree.dataObjects.get(from);
|
||||
fromr.restrictions = new long[it.value().size()];
|
||||
for (int k = 0; k < fromr.restrictions.length; k++) {
|
||||
int to = (int) (it.value().get(k) >> RouteDataObject.RESTRICTION_SHIFT);
|
||||
long valto = (idTables.get(to) << RouteDataObject.RESTRICTION_SHIFT) | ((long) it.value().get(k) & RouteDataObject.RESTRICTION_MASK);
|
||||
fromr.restrictions[k] = valto;
|
||||
}
|
||||
}
|
||||
for (RouteDataObject o : routeTree.dataObjects) {
|
||||
if (o != null) {
|
||||
if (o.id < idTables.size()) {
|
||||
o.id = idTables.get((int) o.id);
|
||||
}
|
||||
if (o.names != null && stringTable != null) {
|
||||
int[] keys = o.names.keys();
|
||||
for (int j = 0; j < keys.length; j++) {
|
||||
o.names.put(keys[j], stringTable.get(o.names.get(keys[j]).charAt(0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
case RouteDataBlock.DATAOBJECTS_FIELD_NUMBER :
|
||||
int length = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
RouteDataObject obj = readRouteDataObject(routeTree.routeReg, routeTree.left, routeTree.top);
|
||||
while(obj.id >= routeTree.dataObjects.size()) {
|
||||
routeTree.dataObjects.add(null);
|
||||
}
|
||||
routeTree.dataObjects.set((int) obj.id,obj);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case RouteDataBlock.IDTABLE_FIELD_NUMBER :
|
||||
long routeId = 0;
|
||||
length = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
idLoop : while(true){
|
||||
int ts = codedIS.readTag();
|
||||
int tags = WireFormat.getTagFieldNumber(ts);
|
||||
switch (tags) {
|
||||
case 0:
|
||||
break idLoop;
|
||||
case IdTable.ROUTEID_FIELD_NUMBER :
|
||||
routeId += codedIS.readSInt64();
|
||||
idTables.add(routeId);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(ts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case RouteDataBlock.RESTRICTIONS_FIELD_NUMBER :
|
||||
length = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
long from = 0;
|
||||
long to = 0;
|
||||
long type = 0;
|
||||
idLoop : while(true){
|
||||
int ts = codedIS.readTag();
|
||||
int tags = WireFormat.getTagFieldNumber(ts);
|
||||
switch (tags) {
|
||||
case 0:
|
||||
break idLoop;
|
||||
case RestrictionData.FROM_FIELD_NUMBER :
|
||||
from = codedIS.readInt32();
|
||||
break;
|
||||
case RestrictionData.TO_FIELD_NUMBER :
|
||||
to = codedIS.readInt32();
|
||||
break;
|
||||
case RestrictionData.TYPE_FIELD_NUMBER :
|
||||
type = codedIS.readInt32();
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(ts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!restrictions.containsKey(from)) {
|
||||
restrictions.put(from, new TLongArrayList());
|
||||
}
|
||||
restrictions.get(from).add((to << RouteDataObject.RESTRICTION_SHIFT) + type);
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case RouteDataBlock.STRINGTABLE_FIELD_NUMBER :
|
||||
length = codedIS.readRawVarint32();
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
stringTable = map.readStringTable();
|
||||
// codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void readRouteEncodingRule(RouteRegion index, int id) throws IOException {
|
||||
String tags = null;
|
||||
String val = null;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
index.initRouteEncodingRule(id, tags, val);
|
||||
return;
|
||||
case RouteEncodingRule.VALUE_FIELD_NUMBER :
|
||||
val = codedIS.readString().intern();
|
||||
break;
|
||||
case RouteEncodingRule.TAG_FIELD_NUMBER :
|
||||
tags = codedIS.readString().intern();
|
||||
break;
|
||||
case RouteEncodingRule.ID_FIELD_NUMBER :
|
||||
id = codedIS.readUInt32();
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RouteSubregion readRouteTree(RouteSubregion thisTree, RouteSubregion parentTree, int depth,
|
||||
boolean readCoordinates) throws IOException {
|
||||
boolean readChildren = depth != 0;
|
||||
if(readChildren) {
|
||||
thisTree.subregions = new ArrayList<BinaryMapRouteReaderAdapter.RouteSubregion>();
|
||||
}
|
||||
thisTree.routeReg.regionsRead++;
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return thisTree;
|
||||
case RouteDataBox.LEFT_FIELD_NUMBER :
|
||||
int i = codedIS.readSInt32();
|
||||
if (readCoordinates) {
|
||||
thisTree.left = i + (parentTree != null ? parentTree.left : 0);
|
||||
}
|
||||
break;
|
||||
case RouteDataBox.RIGHT_FIELD_NUMBER :
|
||||
i = codedIS.readSInt32();
|
||||
if (readCoordinates) {
|
||||
thisTree.right = i + (parentTree != null ? parentTree.right : 0);
|
||||
}
|
||||
break;
|
||||
case RouteDataBox.TOP_FIELD_NUMBER :
|
||||
i = codedIS.readSInt32();
|
||||
if (readCoordinates) {
|
||||
thisTree.top = i + (parentTree != null ? parentTree.top : 0);
|
||||
}
|
||||
break;
|
||||
case RouteDataBox.BOTTOM_FIELD_NUMBER :
|
||||
i = codedIS.readSInt32();
|
||||
if (readCoordinates) {
|
||||
thisTree.bottom = i + (parentTree != null ? parentTree.bottom : 0);
|
||||
}
|
||||
break;
|
||||
case RouteDataBox.SHIFTTODATA_FIELD_NUMBER :
|
||||
thisTree.shiftToData = readInt();
|
||||
if(!readChildren) {
|
||||
// usually 0
|
||||
thisTree.subregions = new ArrayList<BinaryMapRouteReaderAdapter.RouteSubregion>();
|
||||
readChildren = true;
|
||||
}
|
||||
break;
|
||||
case RouteDataBox.BOXES_FIELD_NUMBER :
|
||||
if(readChildren){
|
||||
RouteSubregion subregion = new RouteSubregion(thisTree.routeReg);
|
||||
subregion.length = readInt();
|
||||
subregion.filePointer = codedIS.getTotalBytesRead();
|
||||
int oldLimit = codedIS.pushLimit(subregion.length);
|
||||
readRouteTree(subregion, thisTree, depth - 1, true);
|
||||
thisTree.subregions.add(subregion);
|
||||
codedIS.popLimit(oldLimit);
|
||||
codedIS.seek(subregion.filePointer + subregion.length);
|
||||
} else {
|
||||
codedIS.seek(thisTree.filePointer + thisTree.length);
|
||||
// skipUnknownField(t);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initRouteTypesIfNeeded(SearchRequest<RouteDataObject> req, List<RouteSubregion> list) throws IOException {
|
||||
for (RouteSubregion rs : list) {
|
||||
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
||||
initRouteRegion(rs.routeReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initRouteRegion(RouteRegion routeReg) throws IOException, InvalidProtocolBufferException {
|
||||
if (routeReg.routeEncodingRules.isEmpty()) {
|
||||
codedIS.seek(routeReg.filePointer);
|
||||
int oldLimit = codedIS.pushLimit(routeReg.length);
|
||||
readRouteIndex(routeReg);
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<RouteDataObject> loadRouteRegionData(RouteSubregion rs) throws IOException {
|
||||
TLongArrayList idMap = new TLongArrayList();
|
||||
TLongObjectHashMap<TLongArrayList> restrictionMap = new TLongObjectHashMap<TLongArrayList>();
|
||||
if (rs.dataObjects == null) {
|
||||
codedIS.seek(rs.filePointer + rs.shiftToData);
|
||||
int limit = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(limit);
|
||||
readRouteTreeData(rs, idMap, restrictionMap);
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
List<RouteDataObject> res = rs.dataObjects;
|
||||
rs.dataObjects = null;
|
||||
return res;
|
||||
}
|
||||
|
||||
public void loadRouteRegionData(List<RouteSubregion> toLoad, ResultMatcher<RouteDataObject> matcher) throws IOException {
|
||||
Collections.sort(toLoad, new Comparator<RouteSubregion>() {
|
||||
@Override
|
||||
public int compare(RouteSubregion o1, RouteSubregion o2) {
|
||||
int p1 = o1.filePointer + o1.shiftToData;
|
||||
int p2 = o2.filePointer + o2.shiftToData;
|
||||
return p1 == p2 ? 0 : (p1 < p2 ? -1 : 1);
|
||||
}
|
||||
});
|
||||
TLongArrayList idMap = new TLongArrayList();
|
||||
TLongObjectHashMap<TLongArrayList> restrictionMap = new TLongObjectHashMap<TLongArrayList>();
|
||||
for (RouteSubregion rs : toLoad) {
|
||||
if (rs.dataObjects == null) {
|
||||
codedIS.seek(rs.filePointer + rs.shiftToData);
|
||||
int limit = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(limit);
|
||||
readRouteTreeData(rs, idMap, restrictionMap);
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
for (RouteDataObject ro : rs.dataObjects) {
|
||||
if (ro != null) {
|
||||
matcher.publish(ro);
|
||||
}
|
||||
}
|
||||
// free objects
|
||||
rs.dataObjects = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<RouteSubregion> searchRouteRegionTree(SearchRequest<RouteDataObject> req, List<RouteSubregion> list,
|
||||
List<RouteSubregion> toLoad) throws IOException {
|
||||
for (RouteSubregion rs : list) {
|
||||
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
||||
if (rs.subregions == null) {
|
||||
codedIS.seek(rs.filePointer);
|
||||
int old = codedIS.pushLimit(rs.length);
|
||||
readRouteTree(rs, null, req.contains(rs.left, rs.top, rs.right, rs.bottom) ? -1 : 1, false);
|
||||
codedIS.popLimit(old);
|
||||
}
|
||||
searchRouteRegionTree(req, rs.subregions, toLoad);
|
||||
|
||||
if (rs.shiftToData != 0) {
|
||||
toLoad.add(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return toLoad;
|
||||
}
|
||||
|
||||
public List<RouteDataBorderLinePoint> searchBorderPoints(SearchRequest<RouteDataBorderLinePoint> req, RouteRegion r) throws IOException {
|
||||
if(r.borderBoxPointer != 0) {
|
||||
codedIS.seek(r.borderBoxPointer);
|
||||
int old = codedIS.pushLimit(r.borderBoxLength);
|
||||
TIntArrayList blocksToRead = new TIntArrayList();
|
||||
readBorderLines(req, blocksToRead);
|
||||
|
||||
blocksToRead.sort();
|
||||
for(int j = 0; j< blocksToRead.size() ; j++) {
|
||||
codedIS.seek(blocksToRead.get(j));
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(len);
|
||||
readBorderLinePoints(req, r);
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
codedIS.popLimit(old);
|
||||
|
||||
}
|
||||
return req.getSearchResults();
|
||||
}
|
||||
|
||||
|
||||
private void readBorderLinePoints(SearchRequest<RouteDataBorderLinePoint> req, RouteRegion r) throws IOException {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
long id = 0;
|
||||
while (true) {
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case RouteBorderPointsBlock.X_FIELD_NUMBER: {
|
||||
x = codedIS.readInt32();
|
||||
break;
|
||||
}
|
||||
case RouteBorderPointsBlock.Y_FIELD_NUMBER: {
|
||||
y = codedIS.readInt32();
|
||||
break;
|
||||
}
|
||||
case RouteBorderPointsBlock.BASEID_FIELD_NUMBER: {
|
||||
id = codedIS.readInt64();
|
||||
break;
|
||||
}
|
||||
case RouteBorderPointsBlock.POINTS_FIELD_NUMBER:
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(len);
|
||||
RouteDataBorderLinePoint p = readBorderLinePoint(new RouteDataBorderLinePoint(r), x, y, id);
|
||||
codedIS.popLimit(oldLimit);
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
id = p.id;
|
||||
req.publish(p);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private RouteDataBorderLinePoint readBorderLinePoint(RouteDataBorderLinePoint p, int x, int y, long id) throws IOException {
|
||||
while (true) {
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return p;
|
||||
case RouteBorderPoint.DX_FIELD_NUMBER:
|
||||
p.x = x + codedIS.readInt32();
|
||||
break;
|
||||
case RouteBorderPoint.DY_FIELD_NUMBER:
|
||||
p.y = y + codedIS.readInt32();
|
||||
break;
|
||||
case RouteBorderPoint.ROADID_FIELD_NUMBER:
|
||||
p.id = id + codedIS.readSInt64();
|
||||
break;
|
||||
case RouteBorderPoint.DIRECTION_FIELD_NUMBER:
|
||||
p.direction = codedIS.readBool();
|
||||
break;
|
||||
case RouteBorderPoint.TYPES_FIELD_NUMBER:
|
||||
TIntArrayList types = new TIntArrayList();
|
||||
int len = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(len);
|
||||
while(codedIS.getBytesUntilLimit() > 0) {
|
||||
types.add(codedIS.readRawVarint32());
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
p.types = types.toArray();
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readBorderLines(SearchRequest<RouteDataBorderLinePoint> req, TIntArrayList blocksToRead) throws IOException {
|
||||
while (true) {
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case RouteBorderBox.BORDERLINES_FIELD_NUMBER: {
|
||||
int fp = codedIS.getTotalBytesRead();
|
||||
int length = codedIS.readRawVarint32();
|
||||
int old = codedIS.pushLimit(length);
|
||||
|
||||
RouteBorderLine ln = readBorderLine();
|
||||
if(ln.hasTox() && req.intersects(ln.getX(), ln.getY(), ln.getTox(), ln.getY())) {
|
||||
blocksToRead.add(ln.getShiftToPointsBlock() + fp);
|
||||
// FIXME borders approach
|
||||
// } else if(ln.hasToy() && req.intersects(ln.getX(), ln.getY(), ln.getX(), ln.getToy())) {
|
||||
// blocksToRead.add(ln.getShiftToPointsBlock() + fp);
|
||||
}
|
||||
codedIS.popLimit(old);
|
||||
break;
|
||||
}
|
||||
case RouteBorderBox.BLOCKS_FIELD_NUMBER:
|
||||
return;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private RouteBorderLine readBorderLine() throws IOException {
|
||||
Builder bld = RouteBorderLine.newBuilder();
|
||||
while (true) {
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return bld.build();
|
||||
case RouteBorderLine.X_FIELD_NUMBER:
|
||||
bld.setX(codedIS.readInt32());
|
||||
break;
|
||||
case RouteBorderLine.Y_FIELD_NUMBER:
|
||||
bld.setY(codedIS.readInt32());
|
||||
break;
|
||||
case RouteBorderLine.TOX_FIELD_NUMBER:
|
||||
bld.setTox(codedIS.readInt32());
|
||||
break;
|
||||
case RouteBorderLine.TOY_FIELD_NUMBER:
|
||||
bld.setToy(codedIS.readInt32());
|
||||
break;
|
||||
case RouteBorderLine.SHIFTTOPOINTSBLOCK_FIELD_NUMBER:
|
||||
bld.setShiftToPointsBlock(readInt());
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<RouteSubregion> loadInteresectedPoints(SearchRequest<RouteDataObject> req, List<RouteSubregion> list,
|
||||
List<RouteSubregion> toLoad) throws IOException {
|
||||
for (RouteSubregion rs : list) {
|
||||
if (req.intersects(rs.left, rs.top, rs.right, rs.bottom)) {
|
||||
if (rs.subregions == null) {
|
||||
codedIS.seek(rs.filePointer);
|
||||
int old = codedIS.pushLimit(rs.length);
|
||||
readRouteTree(rs, null, req.contains(rs.left, rs.top, rs.right, rs.bottom) ? -1 : 1, false);
|
||||
codedIS.popLimit(old);
|
||||
}
|
||||
searchRouteRegionTree(req, rs.subregions, toLoad);
|
||||
|
||||
if (rs.shiftToData != 0) {
|
||||
toLoad.add(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return toLoad;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,480 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.data.TransportStop;
|
||||
import net.osmand.util.MapUtils;
|
||||
import net.sf.junidecode.Junidecode;
|
||||
|
||||
import com.google.protobuf.CodedInputStream;
|
||||
import com.google.protobuf.WireFormat;
|
||||
|
||||
public class BinaryMapTransportReaderAdapter {
|
||||
private CodedInputStream codedIS;
|
||||
private final BinaryMapIndexReader map;
|
||||
|
||||
protected BinaryMapTransportReaderAdapter(BinaryMapIndexReader map){
|
||||
this.codedIS = map.codedIS;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
private void skipUnknownField(int t) throws IOException {
|
||||
map.skipUnknownField(t);
|
||||
}
|
||||
|
||||
private int readInt() throws IOException {
|
||||
return map.readInt();
|
||||
}
|
||||
|
||||
public static class TransportIndex extends BinaryIndexPart {
|
||||
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
int top = 0;
|
||||
int bottom = 0;
|
||||
|
||||
int stopsFileOffset = 0;
|
||||
int stopsFileLength = 0;
|
||||
|
||||
public int getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public int getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public int getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public int getBottom() {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
IndexStringTable stringTable = null;
|
||||
}
|
||||
|
||||
protected static class IndexStringTable {
|
||||
int fileOffset = 0;
|
||||
int length = 0;
|
||||
|
||||
// offset from start for each SIZE_OFFSET_ARRAY elements
|
||||
// (SIZE_OFFSET_ARRAY + 1) offset = offsets[0] + skipOneString()
|
||||
TIntArrayList offsets = new TIntArrayList();
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected void readTransportIndex(TransportIndex ind) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.OsmAndTransportIndex.ROUTES_FIELD_NUMBER :
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
case OsmandOdb.OsmAndTransportIndex.NAME_FIELD_NUMBER :
|
||||
ind.setName(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.OsmAndTransportIndex.STOPS_FIELD_NUMBER :
|
||||
ind.stopsFileLength = readInt();
|
||||
ind.stopsFileOffset = codedIS.getTotalBytesRead();
|
||||
int old = codedIS.pushLimit(ind.stopsFileLength);
|
||||
readTransportBounds(ind);
|
||||
codedIS.popLimit(old);
|
||||
break;
|
||||
case OsmandOdb.OsmAndTransportIndex.STRINGTABLE_FIELD_NUMBER :
|
||||
IndexStringTable st = new IndexStringTable();
|
||||
st.length = codedIS.readRawVarint32();
|
||||
st.fileOffset = codedIS.getTotalBytesRead();
|
||||
// Do not cache for now save memory
|
||||
// readStringTable(st, 0, 20, true);
|
||||
ind.stringTable = st;
|
||||
codedIS.seek(st.length + st.fileOffset);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readTransportBounds(TransportIndex ind) throws IOException {
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.TransportStopsTree.LEFT_FIELD_NUMBER :
|
||||
ind.left = codedIS.readSInt32();
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.RIGHT_FIELD_NUMBER :
|
||||
ind.right = codedIS.readSInt32();
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.TOP_FIELD_NUMBER :
|
||||
ind.top = codedIS.readSInt32();
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.BOTTOM_FIELD_NUMBER :
|
||||
ind.bottom = codedIS.readSInt32();
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void searchTransportTreeBounds(int pleft, int pright, int ptop, int pbottom,
|
||||
SearchRequest<TransportStop> req) throws IOException {
|
||||
int init = 0;
|
||||
int lastIndexResult = -1;
|
||||
int cright = 0;
|
||||
int cleft = 0;
|
||||
int ctop = 0;
|
||||
int cbottom = 0;
|
||||
req.numberOfReadSubtrees++;
|
||||
while(true){
|
||||
if(req.isCancelled()){
|
||||
return;
|
||||
}
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
if(init == 0xf){
|
||||
// coordinates are init
|
||||
init = 0;
|
||||
if(cright < req.left || cleft > req.right || ctop > req.bottom || cbottom < req.top){
|
||||
return;
|
||||
} else {
|
||||
req.numberOfAcceptedSubtrees++;
|
||||
}
|
||||
}
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return;
|
||||
case OsmandOdb.TransportStopsTree.BOTTOM_FIELD_NUMBER :
|
||||
cbottom = codedIS.readSInt32() + pbottom;
|
||||
init |= 1;
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.LEFT_FIELD_NUMBER :
|
||||
cleft = codedIS.readSInt32() + pleft;
|
||||
init |= 2;
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.RIGHT_FIELD_NUMBER :
|
||||
cright = codedIS.readSInt32() + pright;
|
||||
init |= 4;
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.TOP_FIELD_NUMBER :
|
||||
ctop = codedIS.readSInt32() + ptop;
|
||||
init |= 8;
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.LEAFS_FIELD_NUMBER :
|
||||
int stopOffset = codedIS.getTotalBytesRead();
|
||||
int length = codedIS.readRawVarint32();
|
||||
int oldLimit = codedIS.pushLimit(length);
|
||||
if(lastIndexResult == -1){
|
||||
lastIndexResult = req.getSearchResults().size();
|
||||
}
|
||||
req.numberOfVisitedObjects++;
|
||||
TransportStop transportStop = readTransportStop(stopOffset, cleft, cright, ctop, cbottom, req);
|
||||
if(transportStop != null){
|
||||
req.publish(transportStop);
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.SUBTREES_FIELD_NUMBER :
|
||||
// left, ... already initialized
|
||||
length = readInt();
|
||||
int filePointer = codedIS.getTotalBytesRead();
|
||||
if (req.limit == -1 || req.limit >= req.getSearchResults().size()) {
|
||||
oldLimit = codedIS.pushLimit(length);
|
||||
searchTransportTreeBounds(cleft, cright, ctop, cbottom, req);
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
codedIS.seek(filePointer + length);
|
||||
|
||||
if(lastIndexResult >= 0){
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.TransportStopsTree.BASEID_FIELD_NUMBER :
|
||||
long baseId = codedIS.readUInt64();
|
||||
if (lastIndexResult != -1) {
|
||||
for (int i = lastIndexResult; i < req.getSearchResults().size(); i++) {
|
||||
TransportStop rs = req.getSearchResults().get(i);
|
||||
rs.setId(rs.getId() + baseId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String regStr(TIntObjectHashMap<String> stringTable) throws IOException{
|
||||
int i = codedIS.readUInt32();
|
||||
stringTable.putIfAbsent(i, "");
|
||||
return ((char) i)+"";
|
||||
}
|
||||
|
||||
public net.osmand.data.TransportRoute getTransportRoute(int filePointer, TIntObjectHashMap<String> stringTable,
|
||||
boolean onlyDescription) throws IOException {
|
||||
codedIS.seek(filePointer);
|
||||
int routeLength = codedIS.readRawVarint32();
|
||||
int old = codedIS.pushLimit(routeLength);
|
||||
net.osmand.data.TransportRoute dataObject = new net.osmand.data.TransportRoute();
|
||||
boolean end = false;
|
||||
long rid = 0;
|
||||
int rx = 0;
|
||||
int ry = 0;
|
||||
long did = 0;
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
while(!end){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
end = true;
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.DISTANCE_FIELD_NUMBER :
|
||||
dataObject.setDistance(codedIS.readUInt32());
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.ID_FIELD_NUMBER :
|
||||
dataObject.setId(codedIS.readUInt64());
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.REF_FIELD_NUMBER :
|
||||
dataObject.setRef(codedIS.readString());
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.TYPE_FIELD_NUMBER :
|
||||
dataObject.setType(regStr(stringTable)); //$NON-NLS-1$
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.NAME_EN_FIELD_NUMBER :
|
||||
dataObject.setEnName(regStr(stringTable)); //$NON-NLS-1$
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.NAME_FIELD_NUMBER :
|
||||
dataObject.setName(regStr(stringTable)); //$NON-NLS-1$
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.OPERATOR_FIELD_NUMBER:
|
||||
dataObject.setOperator(regStr(stringTable)); //$NON-NLS-1$
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.REVERSESTOPS_FIELD_NUMBER:
|
||||
if(onlyDescription){
|
||||
end = true;
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
break;
|
||||
}
|
||||
int length = codedIS.readRawVarint32();
|
||||
int olds = codedIS.pushLimit(length);
|
||||
TransportStop stop = readTransportRouteStop(dx, dy, did, stringTable);
|
||||
dataObject.getBackwardStops().add(stop);
|
||||
did = stop.getId();
|
||||
dx = (int) MapUtils.getTileNumberX(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, stop.getLocation().getLongitude());
|
||||
dy = (int) MapUtils.getTileNumberY(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, stop.getLocation().getLatitude());
|
||||
codedIS.popLimit(olds);
|
||||
break;
|
||||
case OsmandOdb.TransportRoute.DIRECTSTOPS_FIELD_NUMBER:
|
||||
if(onlyDescription){
|
||||
end = true;
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
break;
|
||||
}
|
||||
length = codedIS.readRawVarint32();
|
||||
olds = codedIS.pushLimit(length);
|
||||
stop = readTransportRouteStop(rx, ry, rid, stringTable);
|
||||
dataObject.getForwardStops().add(stop);
|
||||
rid = stop.getId();
|
||||
rx = (int) MapUtils.getTileNumberX(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, stop.getLocation().getLongitude());
|
||||
ry = (int) MapUtils.getTileNumberY(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, stop.getLocation().getLatitude());
|
||||
codedIS.popLimit(olds);
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
codedIS.popLimit(old);
|
||||
|
||||
|
||||
return dataObject;
|
||||
}
|
||||
|
||||
protected void initializeStringTable(TransportIndex ind, TIntObjectHashMap<String> stringTable) throws IOException {
|
||||
int[] values = stringTable.keys();
|
||||
Arrays.sort(values);
|
||||
codedIS.seek(ind.stringTable.fileOffset);
|
||||
int oldLimit = codedIS.pushLimit(ind.stringTable.length);
|
||||
int current = 0;
|
||||
int i = 0;
|
||||
while (i < values.length) {
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
break;
|
||||
case OsmandOdb.StringTable.S_FIELD_NUMBER:
|
||||
if (current == values[i]) {
|
||||
String value = codedIS.readString();
|
||||
stringTable.put(values[i], value);
|
||||
i++;
|
||||
} else {
|
||||
skipUnknownField(t);
|
||||
}
|
||||
current ++;
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
codedIS.popLimit(oldLimit);
|
||||
}
|
||||
|
||||
protected void initializeNames(boolean onlyDescription, net.osmand.data.TransportRoute dataObject,
|
||||
TIntObjectHashMap<String> stringTable) throws IOException {
|
||||
if(dataObject.getName().length() > 0){
|
||||
dataObject.setName(stringTable.get(dataObject.getName().charAt(0)));
|
||||
}
|
||||
if(dataObject.getEnName().length() > 0){
|
||||
dataObject.setEnName(stringTable.get(dataObject.getEnName().charAt(0)));
|
||||
}
|
||||
if(dataObject.getName().length() > 0 && dataObject.getEnName().length() == 0){
|
||||
dataObject.setEnName(Junidecode.unidecode(dataObject.getName()));
|
||||
}
|
||||
|
||||
if(dataObject.getOperator().length() > 0){
|
||||
dataObject.setOperator(stringTable.get(dataObject.getOperator().charAt(0)));
|
||||
}
|
||||
if(dataObject.getType().length() > 0){
|
||||
dataObject.setType(stringTable.get(dataObject.getType().charAt(0)));
|
||||
}
|
||||
for (int i = 0; i < 2 && !onlyDescription; i++) {
|
||||
List<TransportStop> stops = i == 0 ? dataObject.getForwardStops() : dataObject.getBackwardStops();
|
||||
for (TransportStop s : stops) {
|
||||
initializeNames(stringTable, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void initializeNames(TIntObjectHashMap<String> stringTable, TransportStop s) {
|
||||
if (s.getName().length() > 0) {
|
||||
s.setName(stringTable.get(s.getName().charAt(0)));
|
||||
}
|
||||
if (s.getEnName().length() > 0) {
|
||||
s.setEnName(stringTable.get(s.getEnName().charAt(0)));
|
||||
}
|
||||
if (s.getEnName().length() == 0) {
|
||||
s.setEnName(Junidecode.unidecode(s.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private TransportStop readTransportRouteStop(int dx, int dy, long did, TIntObjectHashMap<String> stringTable) throws IOException {
|
||||
TransportStop dataObject = new TransportStop();
|
||||
boolean end = false;
|
||||
while(!end){
|
||||
int t = codedIS.readTag();
|
||||
int tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
end = true;
|
||||
break;
|
||||
case OsmandOdb.TransportRouteStop.NAME_EN_FIELD_NUMBER :
|
||||
dataObject.setEnName(regStr(stringTable)); //$NON-NLS-1$
|
||||
break;
|
||||
case OsmandOdb.TransportRouteStop.NAME_FIELD_NUMBER :
|
||||
dataObject.setName(regStr(stringTable)); //$NON-NLS-1$
|
||||
break;
|
||||
case OsmandOdb.TransportRouteStop.ID_FIELD_NUMBER :
|
||||
did += codedIS.readSInt64();
|
||||
break;
|
||||
case OsmandOdb.TransportRouteStop.DX_FIELD_NUMBER :
|
||||
dx += codedIS.readSInt32();
|
||||
break;
|
||||
case OsmandOdb.TransportRouteStop.DY_FIELD_NUMBER :
|
||||
dy += codedIS.readSInt32();
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
dataObject.setId(did);
|
||||
dataObject.setLocation(MapUtils.getLatitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, dy), MapUtils.getLongitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, dx));
|
||||
return dataObject;
|
||||
}
|
||||
|
||||
private TransportStop readTransportStop(int shift, int cleft, int cright, int ctop, int cbottom, SearchRequest<TransportStop> req) throws IOException {
|
||||
int tag = WireFormat.getTagFieldNumber(codedIS.readTag());
|
||||
if(OsmandOdb.TransportStop.DX_FIELD_NUMBER != tag) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int x = codedIS.readSInt32() + cleft;
|
||||
|
||||
tag = WireFormat.getTagFieldNumber(codedIS.readTag());
|
||||
if(OsmandOdb.TransportStop.DY_FIELD_NUMBER != tag) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int y = codedIS.readSInt32() + ctop;
|
||||
if(req.right < x || req.left > x || req.top > y || req.bottom < y){
|
||||
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
|
||||
return null;
|
||||
}
|
||||
|
||||
req.numberOfAcceptedObjects++;
|
||||
req.cacheTypes.clear();
|
||||
|
||||
TransportStop dataObject = new TransportStop();
|
||||
dataObject.setLocation(MapUtils.getLatitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, y), MapUtils.getLongitudeFromTile(BinaryMapIndexReader.TRANSPORT_STOP_ZOOM, x));
|
||||
dataObject.setFileOffset(shift);
|
||||
while(true){
|
||||
int t = codedIS.readTag();
|
||||
tag = WireFormat.getTagFieldNumber(t);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
dataObject.setReferencesToRoutes(req.cacheTypes.toArray());
|
||||
if(dataObject.getEnName().length() == 0){
|
||||
dataObject.setEnName(Junidecode.unidecode(dataObject.getName()));
|
||||
}
|
||||
return dataObject;
|
||||
case OsmandOdb.TransportStop.ROUTES_FIELD_NUMBER :
|
||||
req.cacheTypes.add(shift - codedIS.readUInt32());
|
||||
break;
|
||||
case OsmandOdb.TransportStop.NAME_EN_FIELD_NUMBER :
|
||||
if (req.stringTable != null) {
|
||||
dataObject.setEnName(regStr(req.stringTable)); //$NON-NLS-1$
|
||||
} else {
|
||||
skipUnknownField(t);
|
||||
}
|
||||
break;
|
||||
case OsmandOdb.TransportStop.NAME_FIELD_NUMBER :
|
||||
if (req.stringTable != null) {
|
||||
dataObject.setName(regStr(req.stringTable)); //$NON-NLS-1$
|
||||
} else {
|
||||
skipUnknownField(t);
|
||||
}
|
||||
|
||||
break;
|
||||
case OsmandOdb.TransportStop.ID_FIELD_NUMBER :
|
||||
dataObject.setId(codedIS.readSInt64());
|
||||
break;
|
||||
default:
|
||||
skipUnknownField(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
327
OsmAnd-java/src/net/osmand/binary/CachedOsmandIndexes.java
Normal file
327
OsmAnd-java/src/net/osmand/binary/CachedOsmandIndexes.java
Normal file
|
@ -0,0 +1,327 @@
|
|||
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);
|
||||
}
|
||||
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(MapUtils.get31TileNumberX(index.getLeftLongitude()));
|
||||
poi.setRight(MapUtils.get31TileNumberX(index.getRightLongitude()));
|
||||
poi.setTop(MapUtils.get31TileNumberY(index.getTopLatitude()));
|
||||
poi.setBottom(MapUtils.get31TileNumberY(index.getBottomLatitude()));
|
||||
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);
|
||||
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);
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
private BinaryMapIndexReader initFileIndex(FileIndex found, RandomAccessFile mf) throws IOException {
|
||||
BinaryMapIndexReader reader = new BinaryMapIndexReader(mf, 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);
|
||||
}
|
||||
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.leftLongitude = MapUtils.get31LongitudeX(index.getLeft());
|
||||
mi.rightLongitude = MapUtils.get31LongitudeX(index.getRight());
|
||||
mi.topLatitude =MapUtils.get31LatitudeY(index.getTop());
|
||||
mi.bottomLatitude = MapUtils.get31LatitudeY(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
5262
OsmAnd-java/src/net/osmand/binary/OsmandIndex.java
Normal file
5262
OsmAnd-java/src/net/osmand/binary/OsmandIndex.java
Normal file
File diff suppressed because it is too large
Load diff
24438
OsmAnd-java/src/net/osmand/binary/OsmandOdb.java
Normal file
24438
OsmAnd-java/src/net/osmand/binary/OsmandOdb.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,75 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||
|
||||
public class RouteDataBorderLinePoint extends RouteDataObject {
|
||||
// all these arrays supposed to be immutable!
|
||||
// These feilds accessible from C++
|
||||
public int x;
|
||||
public int y;
|
||||
public boolean direction;
|
||||
|
||||
// used in context calculation
|
||||
public float distanceToStartPoint;
|
||||
public float distanceToEndPoint;
|
||||
|
||||
public RouteDataBorderLinePoint(RouteRegion region) {
|
||||
super(region);
|
||||
}
|
||||
|
||||
public float getMaximumSpeed(){
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
float maxSpeed = r.maxSpeed();
|
||||
if (maxSpeed > 0) {
|
||||
return maxSpeed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getOneway() {
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
if (r.onewayDirection() != 0) {
|
||||
return r.onewayDirection();
|
||||
} else if (r.roundabout()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
if ("route".equals(r.getTag())) {
|
||||
return r.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getHighway() {
|
||||
String highway = null;
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
highway = r.highwayRoad();
|
||||
if (highway != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return highway;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Border line " + id;
|
||||
}
|
||||
}
|
269
OsmAnd-java/src/net/osmand/binary/RouteDataObject.java
Normal file
269
OsmAnd-java/src/net/osmand/binary/RouteDataObject.java
Normal file
|
@ -0,0 +1,269 @@
|
|||
package net.osmand.binary;
|
||||
|
||||
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteRegion;
|
||||
import net.osmand.binary.BinaryMapRouteReaderAdapter.RouteTypeRule;
|
||||
|
||||
public class RouteDataObject {
|
||||
/*private */static final int RESTRICTION_SHIFT = 3;
|
||||
/*private */static final int RESTRICTION_MASK = 7;
|
||||
|
||||
public final RouteRegion region;
|
||||
// all these arrays supposed to be immutable!
|
||||
// These fields accessible from C++
|
||||
public int[] types;
|
||||
public int[] pointsX;
|
||||
public int[] pointsY;
|
||||
public long[] restrictions;
|
||||
public int[][] pointTypes;
|
||||
public long id;
|
||||
public TIntObjectHashMap<String> names;
|
||||
public final static float NONE_MAX_SPEED = 40f;
|
||||
|
||||
public RouteDataObject(RouteRegion region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public RouteDataObject(RouteRegion region, int[] nameIds, String[] nameValues) {
|
||||
this.region = region;
|
||||
if (nameIds.length > 0) {
|
||||
names = new TIntObjectHashMap<String>();
|
||||
}
|
||||
for (int i = 0; i < nameIds.length; i++) {
|
||||
names.put(nameIds[i], nameValues[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public RouteDataObject(RouteDataObject copy) {
|
||||
this.region = copy.region;
|
||||
this.pointsX = copy.pointsX;
|
||||
this.pointsY = copy.pointsY;
|
||||
this.types = copy.types;
|
||||
this.names = copy.names;
|
||||
this.restrictions = copy.restrictions;
|
||||
this.pointTypes = copy.pointTypes;
|
||||
this.id = copy.id;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
if(names != null ) {
|
||||
return names.get(region.nameTypeRule);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getRef(){
|
||||
if(names != null ) {
|
||||
return names.get(region.refTypeRule);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getDestinationName(){
|
||||
if(names != null ) {
|
||||
return names.get(region.destinationTypeRule);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getPoint31XTile(int i) {
|
||||
return pointsX[i];
|
||||
}
|
||||
|
||||
public int getPoint31YTile(int i) {
|
||||
return pointsY[i];
|
||||
}
|
||||
|
||||
public int getPointsLength() {
|
||||
return pointsX.length;
|
||||
}
|
||||
|
||||
public int getRestrictionLength() {
|
||||
return restrictions == null ? 0 : restrictions.length;
|
||||
}
|
||||
|
||||
public int getRestrictionType(int i) {
|
||||
return (int) (restrictions[i] & RESTRICTION_MASK);
|
||||
}
|
||||
|
||||
public long getRestrictionId(int i) {
|
||||
return restrictions[i] >> RESTRICTION_SHIFT;
|
||||
}
|
||||
|
||||
public void insert(int pos, int x31, int y31) {
|
||||
int[] opointsX = pointsX;
|
||||
int[] opointsY = pointsY;
|
||||
int[][] opointTypes = pointTypes;
|
||||
pointsX = new int[pointsX.length + 1];
|
||||
pointsY = new int[pointsY.length + 1];
|
||||
boolean insTypes = this.pointTypes != null && this.pointTypes.length > pos;
|
||||
if (insTypes) {
|
||||
pointTypes = new int[opointTypes.length + 1][];
|
||||
}
|
||||
int i = 0;
|
||||
for (; i < pos; i++) {
|
||||
pointsX[i] = opointsX[i];
|
||||
pointsY[i] = opointsY[i];
|
||||
if (insTypes) {
|
||||
pointTypes[i] = opointTypes[i];
|
||||
}
|
||||
}
|
||||
pointsX[i] = x31;
|
||||
pointsY[i] = y31;
|
||||
if (insTypes) {
|
||||
pointTypes[i] = null;
|
||||
}
|
||||
for (i = i + 1; i < pointsX.length; i++) {
|
||||
pointsX[i] = opointsX[i - 1];
|
||||
pointsY[i] = opointsY[i - 1];
|
||||
if (insTypes && i < pointTypes.length) {
|
||||
pointTypes[i] = opointTypes[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int[] getPointTypes(int ind) {
|
||||
if (pointTypes == null || ind >= pointTypes.length) {
|
||||
return null;
|
||||
}
|
||||
return pointTypes[ind];
|
||||
}
|
||||
|
||||
public int[] getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
public float getMaximumSpeed(){
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
float maxSpeed = r.maxSpeed();
|
||||
if (maxSpeed > 0) {
|
||||
return maxSpeed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean loop(){
|
||||
return pointsX[0] == pointsX[pointsX.length - 1] && pointsY[0] == pointsY[pointsY.length - 1] ;
|
||||
}
|
||||
|
||||
public boolean roundabout(){
|
||||
int sz = types.length;
|
||||
for(int i=0; i<sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
if(r.roundabout()) {
|
||||
return true;
|
||||
} else if(r.onewayDirection() != 0 && loop()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getOneway() {
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
if (r.onewayDirection() != 0) {
|
||||
return r.onewayDirection();
|
||||
} else if (r.roundabout()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getRoute() {
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
if ("route".equals(r.getTag())) {
|
||||
return r.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getHighway() {
|
||||
return getHighway(types, region);
|
||||
}
|
||||
|
||||
public static String getHighway(int[] types, RouteRegion region) {
|
||||
String highway = null;
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
highway = r.highwayRoad();
|
||||
if (highway != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return highway;
|
||||
}
|
||||
|
||||
public int getLanes() {
|
||||
int sz = types.length;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
RouteTypeRule r = region.quickGetEncodingRule(types[i]);
|
||||
int ln = r.lanes();
|
||||
if (ln > 0) {
|
||||
return ln;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public double directionRoute(int startPoint, boolean plus) {
|
||||
// same goes to C++
|
||||
// Victor : the problem to put more than 5 meters that BinaryRoutePlanner will treat
|
||||
// 2 consequent Turn Right as UT and here 2 points will have same turn angle
|
||||
// So it should be fix in both places
|
||||
return directionRoute(startPoint, plus, 5);
|
||||
}
|
||||
|
||||
// Gives route direction of EAST degrees from NORTH ]-PI, PI]
|
||||
public double directionRoute(int startPoint, boolean plus, float dist) {
|
||||
int x = getPoint31XTile(startPoint);
|
||||
int y = getPoint31YTile(startPoint);
|
||||
int nx = startPoint;
|
||||
int px = x;
|
||||
int py = y;
|
||||
double total = 0;
|
||||
do {
|
||||
if (plus) {
|
||||
nx++;
|
||||
if (nx >= getPointsLength()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nx--;
|
||||
if (nx < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
px = getPoint31XTile(nx);
|
||||
py = getPoint31YTile(nx);
|
||||
// translate into meters
|
||||
total += Math.abs(px - x) * 0.011d + Math.abs(py - y) * 0.01863d;
|
||||
} while (total < dist);
|
||||
return -Math.atan2( x - px, y - py );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = getName();
|
||||
String rf = getRef();
|
||||
return MessageFormat.format("Road id {0} name {1} ref {2}", getId()+"", name == null ? "" : name, rf == null ? "" : rf);
|
||||
}
|
||||
}
|
56
OsmAnd-java/src/net/osmand/bridge/CoreOsmAnd.java
Normal file
56
OsmAnd-java/src/net/osmand/bridge/CoreOsmAnd.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* This file was automatically generated by SWIG (http://www.swig.org).
|
||||
* Version 2.0.7
|
||||
*
|
||||
* Do not make changes to this file unless you know what you are doing--modify
|
||||
* the SWIG interface file instead.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
package net.osmand.bridge;
|
||||
|
||||
public class CoreOsmAnd {
|
||||
public static int get31TileNumberX(double longitude) {
|
||||
return CoreOsmAndJNI.get31TileNumberX(longitude);
|
||||
}
|
||||
|
||||
public static int get31TileNumberY(double latitude) {
|
||||
return CoreOsmAndJNI.get31TileNumberY(latitude);
|
||||
}
|
||||
|
||||
public static double get31LongitudeX(int x) {
|
||||
return CoreOsmAndJNI.get31LongitudeX(x);
|
||||
}
|
||||
|
||||
public static double get31LatitudeY(int y) {
|
||||
return CoreOsmAndJNI.get31LatitudeY(y);
|
||||
}
|
||||
|
||||
public static double getTileNumberX(float zoom, double longitude) {
|
||||
return CoreOsmAndJNI.getTileNumberX(zoom, longitude);
|
||||
}
|
||||
|
||||
public static double getTileNumberY(float zoom, double latitude) {
|
||||
return CoreOsmAndJNI.getTileNumberY(zoom, latitude);
|
||||
}
|
||||
|
||||
public static double checkLatitude(double latitude) {
|
||||
return CoreOsmAndJNI.checkLatitude(latitude);
|
||||
}
|
||||
|
||||
public static double checkLongitude(double longitude) {
|
||||
return CoreOsmAndJNI.checkLongitude(longitude);
|
||||
}
|
||||
|
||||
public static double getPowZoom(float zoom) {
|
||||
return CoreOsmAndJNI.getPowZoom(zoom);
|
||||
}
|
||||
|
||||
public static double getLongitudeFromTile(float zoom, double x) {
|
||||
return CoreOsmAndJNI.getLongitudeFromTile(zoom, x);
|
||||
}
|
||||
|
||||
public static double getLatitudeFromTile(float zoom, double y) {
|
||||
return CoreOsmAndJNI.getLatitudeFromTile(zoom, y);
|
||||
}
|
||||
|
||||
}
|
37
OsmAnd-java/src/net/osmand/bridge/CoreOsmAndJNI.java
Normal file
37
OsmAnd-java/src/net/osmand/bridge/CoreOsmAndJNI.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* This file was automatically generated by SWIG (http://www.swig.org).
|
||||
* Version 2.0.7
|
||||
*
|
||||
* Do not make changes to this file unless you know what you are doing--modify
|
||||
* the SWIG interface file instead.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
package net.osmand.bridge;
|
||||
|
||||
public class CoreOsmAndJNI {
|
||||
public final static native long new_StringVector__SWIG_0();
|
||||
public final static native long new_StringVector__SWIG_1(long jarg1);
|
||||
public final static native long StringVector_size(long jarg1, StringVector jarg1_);
|
||||
public final static native long StringVector_capacity(long jarg1, StringVector jarg1_);
|
||||
public final static native void StringVector_reserve(long jarg1, StringVector jarg1_, long jarg2);
|
||||
public final static native boolean StringVector_isEmpty(long jarg1, StringVector jarg1_);
|
||||
public final static native void StringVector_clear(long jarg1, StringVector jarg1_);
|
||||
public final static native void StringVector_add(long jarg1, StringVector jarg1_, String jarg2);
|
||||
public final static native String StringVector_get(long jarg1, StringVector jarg1_, int jarg2);
|
||||
public final static native void StringVector_set(long jarg1, StringVector jarg1_, int jarg2, String jarg3);
|
||||
public final static native void delete_StringVector(long jarg1);
|
||||
public final static native int ObfInspector_inspector(long jarg1, StringVector jarg1_);
|
||||
public final static native long new_ObfInspector();
|
||||
public final static native void delete_ObfInspector(long jarg1);
|
||||
public final static native int get31TileNumberX(double jarg1);
|
||||
public final static native int get31TileNumberY(double jarg1);
|
||||
public final static native double get31LongitudeX(int jarg1);
|
||||
public final static native double get31LatitudeY(int jarg1);
|
||||
public final static native double getTileNumberX(float jarg1, double jarg2);
|
||||
public final static native double getTileNumberY(float jarg1, double jarg2);
|
||||
public final static native double checkLatitude(double jarg1);
|
||||
public final static native double checkLongitude(double jarg1);
|
||||
public final static native double getPowZoom(float jarg1);
|
||||
public final static native double getLongitudeFromTile(float jarg1, double jarg2);
|
||||
public final static native double getLatitudeFromTile(float jarg1, double jarg2);
|
||||
}
|
46
OsmAnd-java/src/net/osmand/bridge/ObfInspector.java
Normal file
46
OsmAnd-java/src/net/osmand/bridge/ObfInspector.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* This file was automatically generated by SWIG (http://www.swig.org).
|
||||
* Version 2.0.7
|
||||
*
|
||||
* Do not make changes to this file unless you know what you are doing--modify
|
||||
* the SWIG interface file instead.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
package net.osmand.bridge;
|
||||
|
||||
public class ObfInspector {
|
||||
private long swigCPtr;
|
||||
protected boolean swigCMemOwn;
|
||||
|
||||
protected ObfInspector(long cPtr, boolean cMemoryOwn) {
|
||||
swigCMemOwn = cMemoryOwn;
|
||||
swigCPtr = cPtr;
|
||||
}
|
||||
|
||||
protected static long getCPtr(ObfInspector obj) {
|
||||
return (obj == null) ? 0 : obj.swigCPtr;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
delete();
|
||||
}
|
||||
|
||||
public synchronized void delete() {
|
||||
if (swigCPtr != 0) {
|
||||
if (swigCMemOwn) {
|
||||
swigCMemOwn = false;
|
||||
CoreOsmAndJNI.delete_ObfInspector(swigCPtr);
|
||||
}
|
||||
swigCPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int inspector(StringVector argv) {
|
||||
return CoreOsmAndJNI.ObfInspector_inspector(StringVector.getCPtr(argv), argv);
|
||||
}
|
||||
|
||||
public ObfInspector() {
|
||||
this(CoreOsmAndJNI.new_ObfInspector(), true);
|
||||
}
|
||||
|
||||
}
|
84
OsmAnd-java/src/net/osmand/bridge/StringVector.java
Normal file
84
OsmAnd-java/src/net/osmand/bridge/StringVector.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* This file was automatically generated by SWIG (http://www.swig.org).
|
||||
* Version 2.0.7
|
||||
*
|
||||
* Do not make changes to this file unless you know what you are doing--modify
|
||||
* the SWIG interface file instead.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
package net.osmand.bridge;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
|
||||
public class StringVector extends AbstractList<String> {
|
||||
private long swigCPtr;
|
||||
protected boolean swigCMemOwn;
|
||||
|
||||
protected StringVector(long cPtr, boolean cMemoryOwn) {
|
||||
swigCMemOwn = cMemoryOwn;
|
||||
swigCPtr = cPtr;
|
||||
}
|
||||
|
||||
protected static long getCPtr(StringVector obj) {
|
||||
return (obj == null) ? 0 : obj.swigCPtr;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
delete();
|
||||
}
|
||||
|
||||
public synchronized void delete() {
|
||||
if (swigCPtr != 0) {
|
||||
if (swigCMemOwn) {
|
||||
swigCMemOwn = false;
|
||||
CoreOsmAndJNI.delete_StringVector(swigCPtr);
|
||||
}
|
||||
swigCPtr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public StringVector() {
|
||||
this(CoreOsmAndJNI.new_StringVector__SWIG_0(), true);
|
||||
}
|
||||
|
||||
public StringVector(long n) {
|
||||
this(CoreOsmAndJNI.new_StringVector__SWIG_1(n), true);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return (int) CoreOsmAndJNI.StringVector_size(swigCPtr, this);
|
||||
}
|
||||
|
||||
public long capacity() {
|
||||
return CoreOsmAndJNI.StringVector_capacity(swigCPtr, this);
|
||||
}
|
||||
|
||||
public void reserve(long n) {
|
||||
CoreOsmAndJNI.StringVector_reserve(swigCPtr, this, n);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return CoreOsmAndJNI.StringVector_isEmpty(swigCPtr, this);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
CoreOsmAndJNI.StringVector_clear(swigCPtr, this);
|
||||
}
|
||||
|
||||
public boolean add(String x) {
|
||||
CoreOsmAndJNI.StringVector_add(swigCPtr, this, x);
|
||||
return true;
|
||||
}
|
||||
|
||||
public String get(int i) {
|
||||
return CoreOsmAndJNI.StringVector_get(swigCPtr, this, i);
|
||||
}
|
||||
|
||||
public String set(int i, String val) {
|
||||
String prev = CoreOsmAndJNI.StringVector_get(swigCPtr, this, i);
|
||||
CoreOsmAndJNI.StringVector_set(swigCPtr, this, i, val);
|
||||
return prev;
|
||||
}
|
||||
|
||||
}
|
72
OsmAnd-java/src/net/osmand/data/Amenity.java
Normal file
72
OsmAnd-java/src/net/osmand/data/Amenity.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
package net.osmand.data;
|
||||
|
||||
|
||||
public class Amenity extends MapObject {
|
||||
|
||||
private static final long serialVersionUID = 132083949926339552L;
|
||||
private String subType;
|
||||
private AmenityType type;
|
||||
private String openingHours;
|
||||
private String phone;
|
||||
private String description;
|
||||
private String site;
|
||||
|
||||
public Amenity(){
|
||||
}
|
||||
|
||||
public AmenityType getType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getSubType(){
|
||||
return subType;
|
||||
}
|
||||
|
||||
public void setType(AmenityType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setSubType(String subType) {
|
||||
this.subType = subType;
|
||||
}
|
||||
|
||||
public String getOpeningHours() {
|
||||
return openingHours;
|
||||
}
|
||||
|
||||
public void setOpeningHours(String openingHours) {
|
||||
this.openingHours = openingHours;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.toString() + " : " + subType + " "+ getName();
|
||||
}
|
||||
|
||||
public String getSite() {
|
||||
return site;
|
||||
}
|
||||
|
||||
public void setSite(String site) {
|
||||
this.site = site;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
|
||||
}
|
59
OsmAnd-java/src/net/osmand/data/AmenityType.java
Normal file
59
OsmAnd-java/src/net/osmand/data/AmenityType.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
package net.osmand.data;
|
||||
|
||||
// http://wiki.openstreetmap.org/wiki/Amenity
|
||||
// POI tags : amenity, leisure, shop, sport, tourism, historic; accessories (internet-access), natural ?
|
||||
public enum AmenityType {
|
||||
// Some of those types are subtypes of Amenity tag
|
||||
SUSTENANCE("amenity"), // restaurant, cafe ... //$NON-NLS-1$ //$NON-NLS-2$
|
||||
EDUCATION("amenity"), // school, ... //$NON-NLS-1$ //$NON-NLS-2$
|
||||
TRANSPORTATION("amenity"), // car_wash, parking, ... //$NON-NLS-1$ //$NON-NLS-2$
|
||||
FINANCE("amenity"), // bank, atm, ... //$NON-NLS-1$ //$NON-NLS-2$
|
||||
HEALTHCARE("amenity"), // hospital ... //$NON-NLS-1$ //$NON-NLS-2$
|
||||
ENTERTAINMENT("amenity"), // cinema, ... (+! sauna, brothel) //$NON-NLS-1$ //$NON-NLS-2$
|
||||
TOURISM("tourism"), // [TAG] tourism hotel, sights, museum .. //$NON-NLS-1$ //$NON-NLS-2$
|
||||
HISTORIC("historic"), // [TAG] historic places, monuments (should we unify tourism/historic) //$NON-NLS-1$ //$NON-NLS-2$
|
||||
NATURAL("natural"), // [TAG] natural places, monuments (should we unify tourism/historic) //$NON-NLS-1$ //$NON-NLS-2$
|
||||
SHOP("shop"), // [TAG] amenity convenience (product), clothes... //$NON-NLS-1$ //$NON-NLS-2$
|
||||
LEISURE("leisure"), // [TAG] leisure //$NON-NLS-1$ //$NON-NLS-2$
|
||||
SPORT("sport"), // [TAG] sport //$NON-NLS-1$ //$NON-NLS-2$
|
||||
BARRIER("barrier"), // [TAG] barrier + traffic_calming //$NON-NLS-1$ //$NON-NLS-2$
|
||||
LANDUSE("landuse"), // [TAG] landuse //$NON-NLS-1$ //$NON-NLS-2$
|
||||
MAN_MADE("man_made"), // [TAG] man_made and others //$NON-NLS-1$ //$NON-NLS-2$
|
||||
OFFICE("office"), // [TAG] office //$NON-NLS-1$ //$NON-NLS-2$
|
||||
EMERGENCY("emergency"), // [TAG] emergency //$NON-NLS-1$ //$NON-NLS-2$
|
||||
MILITARY("military"), // [TAG] military //$NON-NLS-1$ //$NON-NLS-2$
|
||||
ADMINISTRATIVE("administrative"), // [TAG] administrative //$NON-NLS-1$ //$NON-NLS-2$
|
||||
GEOCACHE("geocache"), //$NON-NLS-1$
|
||||
OSMWIKI("osmwiki"), //$NON-NLS-1$
|
||||
USER_DEFINED("user_defined"), //$NON-NLS-1$
|
||||
OTHER("amenity"), // grave-yard, police, post-office [+Internet_access] //$NON-NLS-1$ //$NON-NLS-2$
|
||||
;
|
||||
|
||||
private final String defaultTag;
|
||||
|
||||
private AmenityType(String defaultTag) {
|
||||
this.defaultTag = defaultTag;
|
||||
}
|
||||
|
||||
public static AmenityType fromString(String s){
|
||||
try {
|
||||
return AmenityType.valueOf(s.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return AmenityType.OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public String getDefaultTag() {
|
||||
return defaultTag;
|
||||
}
|
||||
|
||||
public static String valueToString(AmenityType t){
|
||||
return t.toString().toLowerCase();
|
||||
}
|
||||
|
||||
public static AmenityType[] getCategories(){
|
||||
return AmenityType.values();
|
||||
}
|
||||
|
||||
|
||||
}
|
144
OsmAnd-java/src/net/osmand/data/Building.java
Normal file
144
OsmAnd-java/src/net/osmand/data/Building.java
Normal file
|
@ -0,0 +1,144 @@
|
|||
package net.osmand.data;
|
||||
|
||||
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
public class Building extends MapObject {
|
||||
|
||||
private String postcode;
|
||||
private LatLon latLon2;
|
||||
private BuildingInterpolation interpolationType;
|
||||
private int interpolationInterval;
|
||||
private String name2;
|
||||
|
||||
public enum BuildingInterpolation {
|
||||
ALL(-1), EVEN(-2), ODD(-3), ALPHABETIC(-4);
|
||||
private final int val;
|
||||
|
||||
BuildingInterpolation(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
public int getValue() {
|
||||
return val;
|
||||
}
|
||||
|
||||
public static BuildingInterpolation fromValue(int i){
|
||||
for(BuildingInterpolation b : values()) {
|
||||
if(b.val == i) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Building(){}
|
||||
|
||||
public String getPostcode() {
|
||||
return postcode;
|
||||
}
|
||||
|
||||
public int getInterpolationInterval() {
|
||||
return interpolationInterval;
|
||||
}
|
||||
public void setInterpolationInterval(int interpolationNumber) {
|
||||
this.interpolationInterval = interpolationNumber;
|
||||
}
|
||||
|
||||
public BuildingInterpolation getInterpolationType() {
|
||||
return interpolationType;
|
||||
}
|
||||
|
||||
public void setInterpolationType(BuildingInterpolation interpolationType) {
|
||||
this.interpolationType = interpolationType;
|
||||
}
|
||||
|
||||
public LatLon getLatLon2() {
|
||||
return latLon2;
|
||||
}
|
||||
public void setLatLon2(LatLon latlon2) {
|
||||
this.latLon2 = latlon2;
|
||||
}
|
||||
public String getName2() {
|
||||
return name2;
|
||||
}
|
||||
|
||||
public void setName2(String name2) {
|
||||
this.name2 = name2;
|
||||
}
|
||||
|
||||
public void setPostcode(String postcode) {
|
||||
this.postcode = postcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(boolean en) {
|
||||
String fname = super.getName(en);
|
||||
if(interpolationInterval !=0){
|
||||
return fname+"-"+name2 +" (+"+interpolationInterval+") ";
|
||||
} else if(interpolationType != null) {
|
||||
return fname+"-"+name2 +" ("+interpolationType.toString().toLowerCase()+") ";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public float interpolation(String hno) {
|
||||
if(getInterpolationType() != null || getInterpolationInterval() > 0) {
|
||||
int num = Algorithms.extractFirstIntegerNumber(hno);
|
||||
int numB = Algorithms.extractFirstIntegerNumber(super.getName());
|
||||
int numT = numB;
|
||||
if (num >= numB) {
|
||||
if (getName2() != null) {
|
||||
numT = Algorithms.extractFirstIntegerNumber(getName2());
|
||||
if(numT < num) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (getInterpolationType() == BuildingInterpolation.EVEN && num % 2 == 1) {
|
||||
return -1;
|
||||
}
|
||||
if (getInterpolationType() == BuildingInterpolation.ODD && num % 2 == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (getInterpolationInterval() != 0 && (num - numB) % getInterpolationInterval() != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if(numT > numB){
|
||||
return ((float)num - numB) / (((float)numT - numB));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public boolean belongsToInterpolation(String hno) {
|
||||
return interpolation(hno) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if(interpolationInterval !=0){
|
||||
return name+"-"+name2 +" (+"+interpolationInterval+") ";
|
||||
} else if(interpolationType != null) {
|
||||
return name+"-"+name2 +" ("+interpolationType+") ";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public LatLon getLocation(float interpolation) {
|
||||
LatLon loc = getLocation();
|
||||
LatLon latLon2 = getLatLon2();
|
||||
if (latLon2 != null) {
|
||||
double lat1 = loc.getLatitude();
|
||||
double lat2 = latLon2.getLatitude();
|
||||
double lon1 = loc.getLongitude();
|
||||
double lon2 = latLon2.getLongitude();
|
||||
return new LatLon(interpolation * (lat2 - lat1) + lat1, interpolation * (lon2 - lon1) + lon1);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
}
|
140
OsmAnd-java/src/net/osmand/data/City.java
Normal file
140
OsmAnd-java/src/net/osmand/data/City.java
Normal file
|
@ -0,0 +1,140 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
public class City extends MapObject {
|
||||
public enum CityType {
|
||||
// that's tricky way to play with that numbers (to avoid including suburbs in city & vice verse)
|
||||
// district special type and it is not registered as a city
|
||||
CITY(10000), TOWN(5000), VILLAGE(1300), HAMLET(1000), SUBURB(400), DISTRICT(400);
|
||||
|
||||
private double radius;
|
||||
|
||||
private CityType(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public double getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public static String valueToString(CityType t) {
|
||||
return t.toString().toLowerCase();
|
||||
}
|
||||
|
||||
public static CityType valueFromString(String place) {
|
||||
if (place == null) {
|
||||
return null;
|
||||
}
|
||||
for (CityType t : CityType.values()) {
|
||||
if (t.name().equalsIgnoreCase(place)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private CityType type = null;
|
||||
// Be attentive ! Working with street names ignoring case
|
||||
private Map<String, Street> streets = new TreeMap<String, Street>(PlatformUtil.primaryCollator());
|
||||
private String isin = null;
|
||||
private String postcode = null;
|
||||
|
||||
private static long POSTCODE_INTERNAL_ID = -1000;
|
||||
public static City createPostcode(String postcode){
|
||||
return new City(postcode, POSTCODE_INTERNAL_ID--);
|
||||
}
|
||||
|
||||
public City(CityType type) {
|
||||
if(type == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public City(String postcode, long id) {
|
||||
this.type = null;
|
||||
this.name = this.enName = postcode;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getIsInValue() {
|
||||
return isin;
|
||||
}
|
||||
|
||||
public boolean isPostcode(){
|
||||
return type == null;
|
||||
}
|
||||
|
||||
public boolean isEmptyWithStreets() {
|
||||
return streets.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
public Street unregisterStreet(String name) {
|
||||
return streets.remove(name.toLowerCase());
|
||||
}
|
||||
|
||||
public void removeAllStreets() {
|
||||
streets.clear();
|
||||
}
|
||||
|
||||
public String getPostcode() {
|
||||
return postcode;
|
||||
}
|
||||
|
||||
public void setPostcode(String postcode) {
|
||||
this.postcode = postcode;
|
||||
}
|
||||
|
||||
protected Street registerStreet(Street street, boolean en) {
|
||||
String name = en ? street.getEnName() : street.getName();
|
||||
name = name.toLowerCase();
|
||||
if (!Algorithms.isEmpty(name)) {
|
||||
if (!streets.containsKey(name)) {
|
||||
return streets.put(name, street);
|
||||
} else {
|
||||
// try to merge streets
|
||||
Street prev = streets.get(name);
|
||||
prev.mergeWith(street);
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Street registerStreet(Street street) {
|
||||
return registerStreet(street, false);
|
||||
}
|
||||
|
||||
public CityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Collection<Street> getStreets() {
|
||||
return streets.values();
|
||||
}
|
||||
|
||||
public Street getStreet(String name) {
|
||||
return streets.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if(isPostcode()) {
|
||||
return "Postcode : " + getName(); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
return "City [" + type + "] " + getName(); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
public void setIsin(String isin) {
|
||||
this.isin = isin;
|
||||
}
|
||||
|
||||
}
|
205
OsmAnd-java/src/net/osmand/data/DataTileManager.java
Normal file
205
OsmAnd-java/src/net/osmand/data/DataTileManager.java
Normal file
|
@ -0,0 +1,205 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import gnu.trove.map.hash.TLongObjectHashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> - object to store in that manager
|
||||
*/
|
||||
public class DataTileManager<T> {
|
||||
|
||||
private final int zoom;
|
||||
|
||||
private TLongObjectHashMap<List<T>> objects = new TLongObjectHashMap<List<T>>();
|
||||
|
||||
public DataTileManager(){
|
||||
zoom = 15;
|
||||
}
|
||||
|
||||
public DataTileManager(int z){
|
||||
zoom = z;
|
||||
}
|
||||
|
||||
public int getZoom() {
|
||||
return zoom;
|
||||
}
|
||||
|
||||
|
||||
public boolean isEmpty(){
|
||||
return getObjectsCount() == 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public int getObjectsCount(){
|
||||
int x = 0;
|
||||
for(List s : objects.valueCollection()){
|
||||
x += s.size();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
private void putObjects(int tx, int ty, List<T> r){
|
||||
if(objects.containsKey(evTile(tx, ty))){
|
||||
r.addAll(objects.get(evTile(tx, ty)));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public List<T> getAllObjects(){
|
||||
List<T> l = new ArrayList<T>();
|
||||
for(List s : objects.valueCollection()){
|
||||
l.addAll(s);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<T> getObjects(double latitudeUp, double longitudeUp, double latitudeDown, double longitudeDown) {
|
||||
int tileXUp = (int) MapUtils.getTileNumberX(zoom, longitudeUp);
|
||||
int tileYUp = (int) MapUtils.getTileNumberY(zoom, latitudeUp);
|
||||
int tileXDown = (int) MapUtils.getTileNumberX(zoom, longitudeDown) + 1;
|
||||
int tileYDown = (int) MapUtils.getTileNumberY(zoom, latitudeDown) + 1;
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (int i = tileXUp; i <= tileXDown; i++) {
|
||||
for (int j = tileYUp; j <= tileYDown; j++) {
|
||||
putObjects(i, j, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<T> getObjects(int leftX31, int topY31, int rightX31, int bottomY31) {
|
||||
int tileXUp = leftX31 >> (31 - zoom);
|
||||
int tileYUp = topY31 >> (31 - zoom);
|
||||
int tileXDown = (rightX31 >> (31 - zoom)) + 1;
|
||||
int tileYDown = (bottomY31 >> (31 - zoom)) + 1;
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (int i = tileXUp; i <= tileXDown; i++) {
|
||||
for (int j = tileYUp; j <= tileYDown; j++) {
|
||||
putObjects(i, j, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depth of the neighbor tile to visit
|
||||
* returns not exactly sorted list,
|
||||
* however the first objects are from closer tile than last
|
||||
*/
|
||||
public List<T> getClosestObjects(double latitude, double longitude, int defaultStep){
|
||||
if(isEmpty()){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
int dp = 0;
|
||||
List<T> l = null;
|
||||
while (l == null || l.isEmpty()) {
|
||||
l = getClosestObjects(latitude, longitude, dp, dp + defaultStep);
|
||||
dp += defaultStep;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public List<T> getClosestObjects(double latitude, double longitude){
|
||||
return getClosestObjects(latitude, longitude, 3);
|
||||
}
|
||||
|
||||
public List<T> getClosestObjects(double latitude, double longitude, int startDepth, int depth){
|
||||
int tileX = (int) MapUtils.getTileNumberX(zoom, longitude);
|
||||
int tileY = (int) MapUtils.getTileNumberY(zoom, latitude);
|
||||
List<T> result = new ArrayList<T>();
|
||||
|
||||
if(startDepth <= 0){
|
||||
putObjects(tileX, tileY, result);
|
||||
startDepth = 1;
|
||||
}
|
||||
|
||||
// that's very difficult way visiting node :
|
||||
// similar to visit by spiral
|
||||
// however the simplest way could be to visit row by row & after sort tiles by distance (that's less efficient)
|
||||
|
||||
// go through circle
|
||||
for (int i = startDepth; i <= depth; i++) {
|
||||
|
||||
// goes
|
||||
for (int j = 0; j <= i; j++) {
|
||||
// left & right
|
||||
int dx = j == 0 ? 0 : -1;
|
||||
for (; dx < 1 || (j < i && dx == 1); dx += 2) {
|
||||
// north
|
||||
putObjects(tileX + dx * j, tileY + i, result);
|
||||
// east
|
||||
putObjects(tileX + i, tileY - dx * j, result);
|
||||
// south
|
||||
putObjects(tileX - dx * j, tileY - i, result);
|
||||
// west
|
||||
putObjects(tileX - i, tileY + dx * j, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private long evTile(int tileX, int tileY){
|
||||
long tx = tileX;
|
||||
long ty = tileY;
|
||||
return ((tx) << zoom) + ty;
|
||||
}
|
||||
|
||||
|
||||
public long evaluateTile(double latitude, double longitude){
|
||||
int tileX = (int) MapUtils.getTileNumberX(zoom, longitude);
|
||||
int tileY = (int) MapUtils.getTileNumberY(zoom, latitude);
|
||||
return evTile(tileX, tileY);
|
||||
}
|
||||
|
||||
public long evaluateTileXY(int x31, int y31){
|
||||
return evTile(x31 >> (31 - zoom), y31 >> (31 - zoom));
|
||||
}
|
||||
|
||||
public void unregisterObject(double latitude, double longitude, T object){
|
||||
long tile = evaluateTile(latitude, longitude);
|
||||
removeObject(object, tile);
|
||||
}
|
||||
|
||||
|
||||
public void unregisterObjectXY(int x31, int y31, T object){
|
||||
long tile = evaluateTileXY(x31, y31);
|
||||
removeObject(object, tile);
|
||||
}
|
||||
|
||||
private void removeObject(T object, long tile) {
|
||||
if(objects.containsKey(tile)){
|
||||
objects.get(tile).remove(object);
|
||||
}
|
||||
}
|
||||
|
||||
public long registerObjectXY(int x31, int y31, T object){
|
||||
return addObject(object, evTile(x31 >> (31 - zoom), y31 >> (31 - zoom)));
|
||||
}
|
||||
|
||||
public long registerObject(double latitude, double longitude, T object){
|
||||
long tile = evaluateTile(latitude, longitude);
|
||||
return addObject(object, tile);
|
||||
}
|
||||
|
||||
private long addObject(T object, long tile) {
|
||||
if(!objects.containsKey(tile)){
|
||||
objects.put(tile, new ArrayList<T>());
|
||||
}
|
||||
objects.get(tile).add(object);
|
||||
return tile;
|
||||
}
|
||||
|
||||
|
||||
public void clear(){
|
||||
objects.clear();
|
||||
}
|
||||
|
||||
|
||||
}
|
67
OsmAnd-java/src/net/osmand/data/FavouritePoint.java
Normal file
67
OsmAnd-java/src/net/osmand/data/FavouritePoint.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class FavouritePoint implements Serializable {
|
||||
private static final long serialVersionUID = 729654300829771466L;
|
||||
private String name;
|
||||
private String category = "";
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
private boolean stored = false;
|
||||
|
||||
|
||||
public FavouritePoint(){
|
||||
}
|
||||
|
||||
public FavouritePoint(double latitude, double longitude, String name, String category) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.category = category;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public boolean isStored() {
|
||||
return stored;
|
||||
}
|
||||
public void setStored(boolean stored) {
|
||||
this.stored = stored;
|
||||
}
|
||||
|
||||
public void setLatitude(double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Favourite " + getName(); //$NON-NLS-1$
|
||||
}
|
||||
}
|
54
OsmAnd-java/src/net/osmand/data/LatLon.java
Normal file
54
OsmAnd-java/src/net/osmand/data/LatLon.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
package net.osmand.data;
|
||||
|
||||
|
||||
public class LatLon {
|
||||
private final double longitude;
|
||||
private final double latitude;
|
||||
|
||||
public LatLon(double latitude, double longitude) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(latitude);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(longitude);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
LatLon other = (LatLon) obj;
|
||||
if (Double.doubleToLongBits(latitude) != Double.doubleToLongBits(other.latitude))
|
||||
return false;
|
||||
if (Double.doubleToLongBits(longitude) != Double.doubleToLongBits(other.longitude))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Lat " + ((float)latitude) + " Lon " + ((float)longitude); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
}
|
127
OsmAnd-java/src/net/osmand/data/MapObject.java
Normal file
127
OsmAnd-java/src/net/osmand/data/MapObject.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
package net.osmand.data;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
import net.osmand.Collator;
|
||||
import net.osmand.PlatformUtil;
|
||||
|
||||
|
||||
public abstract class MapObject implements Comparable<MapObject>, Serializable {
|
||||
protected String name = null;
|
||||
protected String enName = null;
|
||||
protected LatLon location = null;
|
||||
protected int fileOffset = 0;
|
||||
protected Long id = null;
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
if(id != null){
|
||||
return id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName(boolean en){
|
||||
if(en){
|
||||
return getEnName();
|
||||
} else {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (this.name != null) {
|
||||
return this.name;
|
||||
}
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEnName() {
|
||||
if(this.enName != null){
|
||||
return this.enName;
|
||||
}
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public void setEnName(String enName) {
|
||||
this.enName = enName;
|
||||
}
|
||||
|
||||
public LatLon getLocation(){
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(double latitude, double longitude){
|
||||
location = new LatLon(latitude, longitude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MapObject o) {
|
||||
return PlatformUtil.primaryCollator().compare(getName(), o.getName());
|
||||
}
|
||||
|
||||
public int getFileOffset() {
|
||||
return fileOffset;
|
||||
}
|
||||
|
||||
public void setFileOffset(int fileOffset) {
|
||||
this.fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " " + name +"("+id+")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
MapObject other = (MapObject) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class MapObjectComparator implements Comparator<MapObject>{
|
||||
private final boolean en;
|
||||
Collator collator = PlatformUtil.primaryCollator();
|
||||
public MapObjectComparator(boolean en){
|
||||
this.en = en;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(MapObject o1, MapObject o2) {
|
||||
if(en){
|
||||
return collator.compare(o1.getEnName(), o2.getEnName());
|
||||
} else {
|
||||
return collator.compare(o1.getName(), o2.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
OsmAnd-java/src/net/osmand/data/QuadPoint.java
Normal file
24
OsmAnd-java/src/net/osmand/data/QuadPoint.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package net.osmand.data;
|
||||
|
||||
public class QuadPoint {
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public QuadPoint() {
|
||||
}
|
||||
|
||||
public QuadPoint(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public QuadPoint(QuadPoint a) {
|
||||
this(a.x, a.y);
|
||||
}
|
||||
|
||||
public void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
}
|
67
OsmAnd-java/src/net/osmand/data/QuadRect.java
Normal file
67
OsmAnd-java/src/net/osmand/data/QuadRect.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
package net.osmand.data;
|
||||
|
||||
public class QuadRect {
|
||||
public float left;
|
||||
public float right;
|
||||
public float top;
|
||||
public float bottom;
|
||||
|
||||
public QuadRect(float left, float top, float right, float bottom) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.top = top;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public QuadRect(QuadRect a) {
|
||||
this(a.left, a.top, a.right, a.bottom);
|
||||
}
|
||||
|
||||
public QuadRect() {
|
||||
}
|
||||
|
||||
public float width() {
|
||||
return right - left;
|
||||
}
|
||||
|
||||
public float height() {
|
||||
return bottom - top;
|
||||
}
|
||||
|
||||
public boolean contains(float left, float top, float right, float bottom) {
|
||||
return this.left < this.right && this.top < this.bottom && this.left <= left && this.top <= top && this.right >= right
|
||||
&& this.bottom >= bottom;
|
||||
}
|
||||
|
||||
public boolean contains(QuadRect box) {
|
||||
return contains(box.left, box.top, box.right, box.bottom);
|
||||
}
|
||||
|
||||
public static boolean intersects(QuadRect a, QuadRect b) {
|
||||
return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
|
||||
}
|
||||
|
||||
public float centerX() {
|
||||
return (left + right) / 2;
|
||||
}
|
||||
|
||||
public float centerY() {
|
||||
return (top + bottom) / 2;
|
||||
}
|
||||
|
||||
public void offset(float dx, float dy) {
|
||||
left += dx;
|
||||
top += dy;
|
||||
right += dx;
|
||||
bottom += dy;
|
||||
|
||||
}
|
||||
|
||||
public void inset(float dx, float dy) {
|
||||
left += dx;
|
||||
top += dy;
|
||||
right -= dx;
|
||||
bottom -= dy;
|
||||
}
|
||||
|
||||
}
|
102
OsmAnd-java/src/net/osmand/data/QuadTree.java
Normal file
102
OsmAnd-java/src/net/osmand/data/QuadTree.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
|
||||
|
||||
public class QuadTree<T> {
|
||||
|
||||
private static class Node<T> {
|
||||
List<T> data = null;
|
||||
Node<T>[] children = null;
|
||||
QuadRect bounds;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Node(QuadRect b) {
|
||||
bounds = new QuadRect(b.left, b.top, b.right, b.bottom);
|
||||
children = new Node[4];
|
||||
}
|
||||
};
|
||||
|
||||
private float ratio;
|
||||
private int maxDepth;
|
||||
private Node<T> root;
|
||||
|
||||
public QuadTree(QuadRect r, int depth/* =8 */, float ratio /* = 0.55 */) {
|
||||
this.ratio = ratio;
|
||||
this.root = new Node<T>(r);
|
||||
this.maxDepth = depth;
|
||||
}
|
||||
|
||||
public void insert(T data, QuadRect box) {
|
||||
int depth = 0;
|
||||
doInsertData(data, box, root, depth);
|
||||
}
|
||||
|
||||
public void insert(T data, float x, float y) {
|
||||
insert(data, new QuadRect(x, y, x, y));
|
||||
}
|
||||
|
||||
public void queryInBox(QuadRect box, List<T> result) {
|
||||
result.clear();
|
||||
queryNode(box, result, root);
|
||||
}
|
||||
|
||||
private void queryNode(QuadRect box, List<T> result, Node<T> node) {
|
||||
if (node != null) {
|
||||
if (QuadRect.intersects(box, node.bounds)) {
|
||||
if (node.data != null) {
|
||||
result.addAll(node.data);
|
||||
}
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
queryNode(box, result, node.children[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doInsertData(T data, QuadRect box, Node<T> n, int depth) {
|
||||
if (++depth >= maxDepth) {
|
||||
if (n.data == null) {
|
||||
n.data = new ArrayList<T>();
|
||||
}
|
||||
n.data.add(data);
|
||||
} else {
|
||||
QuadRect[] ext = new QuadRect[4];
|
||||
splitBox(n.bounds, ext);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (ext[i].contains(box)) {
|
||||
if (n.children[i] == null) {
|
||||
n.children[i] = new Node<T>(ext[i]);
|
||||
}
|
||||
doInsertData(data, box, n.children[i], depth);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (n.data == null) {
|
||||
n.data = new ArrayList<T>();
|
||||
}
|
||||
n.data.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
void splitBox(QuadRect node_extent, QuadRect[] n) {
|
||||
// coord2d c=node_extent.center();
|
||||
|
||||
float width = node_extent.width();
|
||||
float height = node_extent.height();
|
||||
|
||||
float lox = node_extent.left;
|
||||
float loy = node_extent.top;
|
||||
float hix = node_extent.right;
|
||||
float hiy = node_extent.bottom;
|
||||
|
||||
n[0] = new QuadRect(lox, loy, lox + width * ratio, loy + height * ratio);
|
||||
n[1] = new QuadRect(hix - width * ratio, loy, hix, loy + height * ratio);
|
||||
n[2] = new QuadRect(lox, hiy - height * ratio, lox + width * ratio, hiy);
|
||||
n[3] = new QuadRect(hix - width * ratio, hiy - height * ratio, hix, hiy);
|
||||
}
|
||||
|
||||
}
|
102
OsmAnd-java/src/net/osmand/data/Street.java
Normal file
102
OsmAnd-java/src/net/osmand/data/Street.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
|
||||
public class Street extends MapObject {
|
||||
|
||||
protected List<Building> buildings = new ArrayList<Building>();
|
||||
protected List<Street> intersectedStreets = null;
|
||||
protected final City city;
|
||||
|
||||
public Street(City city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public void addBuilding(Building building){
|
||||
buildings.add(building);
|
||||
}
|
||||
|
||||
public List<Street> getIntersectedStreets() {
|
||||
if(intersectedStreets == null){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return intersectedStreets;
|
||||
}
|
||||
|
||||
public void addIntersectedStreet(Street s){
|
||||
if(intersectedStreets == null) {
|
||||
intersectedStreets = new ArrayList<Street>();
|
||||
}
|
||||
intersectedStreets.add(s);
|
||||
}
|
||||
|
||||
public void addBuildingCheckById(Building building){
|
||||
for(Building b : buildings) {
|
||||
if(b.getId().longValue() == building.getId().longValue()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
buildings.add(building);
|
||||
}
|
||||
|
||||
public List<Building> getBuildings() {
|
||||
return buildings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
if (name.equals(getName())) {
|
||||
return;
|
||||
}
|
||||
if (city != null && city.getStreet(getName()) == this) {
|
||||
city.unregisterStreet(getName());
|
||||
super.setName(name);
|
||||
Street s = city.registerStreet(this);
|
||||
} else {
|
||||
super.setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameWithoutCityPart(boolean en) {
|
||||
String nm = getName(en);
|
||||
int t = nm.lastIndexOf('(');
|
||||
if(t > 0) {
|
||||
return nm.substring(0, t);
|
||||
}
|
||||
return nm;
|
||||
|
||||
}
|
||||
|
||||
public City getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void sortBuildings(){
|
||||
Collections.sort(buildings, new Comparator<Building>(){
|
||||
@Override
|
||||
public int compare(Building o1, Building o2) {
|
||||
String s1 = o1.getName();
|
||||
String s2 = o2.getName();
|
||||
int i1 = Algorithms.extractFirstIntegerNumber(s1);
|
||||
int i2 = Algorithms.extractFirstIntegerNumber(s2);
|
||||
if(i1 == i2) {
|
||||
String t1 = Algorithms.extractIntegerSuffix(s1);
|
||||
String t2 = Algorithms.extractIntegerSuffix(s2);
|
||||
return t1.compareTo(t2);
|
||||
}
|
||||
return i1 - i2;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void mergeWith(Street street) {
|
||||
buildings.addAll(street.getBuildings());
|
||||
}
|
||||
|
||||
}
|
74
OsmAnd-java/src/net/osmand/data/TransportRoute.java
Normal file
74
OsmAnd-java/src/net/osmand/data/TransportRoute.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
public class TransportRoute extends MapObject {
|
||||
private List<TransportStop> forwardStops = new ArrayList<TransportStop>();
|
||||
private List<TransportStop> backwardStops = new ArrayList<TransportStop>();
|
||||
private String ref;
|
||||
private String operator;
|
||||
private String type;
|
||||
private Integer dist = null;
|
||||
|
||||
public TransportRoute(){
|
||||
}
|
||||
|
||||
public List<TransportStop> getForwardStops() {
|
||||
return forwardStops;
|
||||
}
|
||||
|
||||
public List<TransportStop> getBackwardStops() {
|
||||
return backwardStops;
|
||||
}
|
||||
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public void setRef(String ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getDistance(){
|
||||
if(dist == null){
|
||||
dist = getAvgBothDistance();
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
public void setDistance(Integer dist) {
|
||||
this.dist = dist;
|
||||
}
|
||||
|
||||
public int getAvgBothDistance(){
|
||||
int d = 0;
|
||||
int bSsize = backwardStops.size();
|
||||
int fSsize = forwardStops.size();
|
||||
for(int i=1; i< bSsize; i++){
|
||||
d += MapUtils.getDistance(backwardStops.get(i-1).getLocation(), backwardStops.get(i).getLocation());
|
||||
}
|
||||
for(int i=1; i< fSsize; i++){
|
||||
d += MapUtils.getDistance(forwardStops.get(i-1).getLocation(), forwardStops.get(i).getLocation());
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
17
OsmAnd-java/src/net/osmand/data/TransportStop.java
Normal file
17
OsmAnd-java/src/net/osmand/data/TransportStop.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package net.osmand.data;
|
||||
|
||||
public class TransportStop extends MapObject {
|
||||
int[] referencesToRoutes = null;
|
||||
|
||||
public TransportStop(){
|
||||
}
|
||||
|
||||
public int[] getReferencesToRoutes() {
|
||||
return referencesToRoutes;
|
||||
}
|
||||
|
||||
public void setReferencesToRoutes(int[] referencesToRoutes) {
|
||||
this.referencesToRoutes = referencesToRoutes;
|
||||
}
|
||||
|
||||
}
|
5
OsmAnd-java/src/net/osmand/map/IMapLocationListener.java
Normal file
5
OsmAnd-java/src/net/osmand/map/IMapLocationListener.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package net.osmand.map;
|
||||
|
||||
public interface IMapLocationListener {
|
||||
void locationChanged(double newLatitude, double newLongitude, Object source);
|
||||
}
|
24
OsmAnd-java/src/net/osmand/map/ITileSource.java
Normal file
24
OsmAnd-java/src/net/osmand/map/ITileSource.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package net.osmand.map;
|
||||
|
||||
|
||||
public interface ITileSource {
|
||||
|
||||
public int getMaximumZoomSupported();
|
||||
|
||||
public String getName();
|
||||
|
||||
public int getTileSize();
|
||||
|
||||
public String getUrlToLoad(int x, int y, int zoom);
|
||||
|
||||
public int getMinimumZoomSupported();
|
||||
|
||||
public String getTileFormat();
|
||||
|
||||
public int getBitDensity();
|
||||
|
||||
public boolean isEllipticYTile();
|
||||
|
||||
public boolean couldBeDownloadedFromInternet();
|
||||
|
||||
}
|
230
OsmAnd-java/src/net/osmand/map/MapTileDownloader.java
Normal file
230
OsmAnd-java/src/net/osmand/map/MapTileDownloader.java
Normal file
|
@ -0,0 +1,230 @@
|
|||
package net.osmand.map;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
|
||||
public class MapTileDownloader {
|
||||
// Download manager tile settings
|
||||
public static int TILE_DOWNLOAD_THREADS = 4;
|
||||
public static int TILE_DOWNLOAD_SECONDS_TO_WORK = 25;
|
||||
public static final long TIMEOUT_AFTER_EXCEEDING_LIMIT_ERRORS = 20000;
|
||||
public static final int TILE_DOWNLOAD_MAX_ERRORS_PER_TIMEOUT = 25;
|
||||
|
||||
|
||||
private static MapTileDownloader downloader = null;
|
||||
private static Log log = PlatformUtil.getLog(MapTileDownloader.class);
|
||||
|
||||
public static String USER_AGENT = "OsmAnd~";
|
||||
|
||||
|
||||
private ThreadPoolExecutor threadPoolExecutor;
|
||||
private List<IMapDownloaderCallback> callbacks = new ArrayList<IMapDownloaderCallback>();
|
||||
|
||||
private Set<File> currentlyDownloaded;
|
||||
|
||||
private int currentErrors = 0;
|
||||
private long timeForErrorCounter = 0;
|
||||
|
||||
|
||||
public static MapTileDownloader getInstance(String userAgent){
|
||||
if(downloader == null){
|
||||
downloader = new MapTileDownloader(TILE_DOWNLOAD_THREADS);
|
||||
if(userAgent != null) {
|
||||
MapTileDownloader.USER_AGENT = userAgent;
|
||||
}
|
||||
}
|
||||
return downloader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for map downloader
|
||||
*/
|
||||
public interface IMapDownloaderCallback {
|
||||
|
||||
/**
|
||||
* Sometimes null cold be passed as request
|
||||
* That means that there were a lot of requests but
|
||||
* once method is called
|
||||
* (in order to not create a collection of request & reduce calling times)
|
||||
* @param fileSaved
|
||||
*/
|
||||
public void tileDownloaded(DownloadRequest request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download request could subclassed to create own detailed request
|
||||
*/
|
||||
public static class DownloadRequest {
|
||||
public final File fileToSave;
|
||||
public final int zoom;
|
||||
public final int xTile;
|
||||
public final int yTile;
|
||||
public final String url;
|
||||
public boolean error;
|
||||
|
||||
public DownloadRequest(String url, File fileToSave, int xTile, int yTile, int zoom) {
|
||||
this.url = url;
|
||||
this.fileToSave = fileToSave;
|
||||
this.xTile = xTile;
|
||||
this.yTile = yTile;
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
public DownloadRequest(String url, File fileToSave) {
|
||||
this.url = url;
|
||||
this.fileToSave = fileToSave;
|
||||
xTile = -1;
|
||||
yTile = -1;
|
||||
zoom = -1;
|
||||
}
|
||||
|
||||
public void setError(boolean error){
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public MapTileDownloader(int numberOfThreads){
|
||||
threadPoolExecutor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, TILE_DOWNLOAD_SECONDS_TO_WORK,
|
||||
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
// 1.6 method but very useful to kill non-running threads
|
||||
// threadPoolExecutor.allowCoreThreadTimeOut(true);
|
||||
currentlyDownloaded = Collections.synchronizedSet(new HashSet<File>());
|
||||
|
||||
}
|
||||
|
||||
public void addDownloaderCallback(IMapDownloaderCallback callback){
|
||||
callbacks.add(callback);
|
||||
}
|
||||
|
||||
public void removeDownloaderCallback(IMapDownloaderCallback callback){
|
||||
callbacks.remove(callback);
|
||||
}
|
||||
|
||||
public List<IMapDownloaderCallback> getDownloaderCallbacks() {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
public boolean isFileCurrentlyDownloaded(File f){
|
||||
return currentlyDownloaded.contains(f);
|
||||
}
|
||||
|
||||
public boolean isSomethingBeingDownloaded(){
|
||||
return !currentlyDownloaded.isEmpty();
|
||||
}
|
||||
|
||||
public int getRemainingWorkers(){
|
||||
return (int) (threadPoolExecutor.getTaskCount());
|
||||
}
|
||||
|
||||
public void refuseAllPreviousRequests(){
|
||||
// That's very strange because exception in impl of queue (possibly wrong impl)
|
||||
// threadPoolExecutor.getQueue().clear();
|
||||
while(!threadPoolExecutor.getQueue().isEmpty()){
|
||||
threadPoolExecutor.getQueue().poll();
|
||||
}
|
||||
}
|
||||
|
||||
public void requestToDownload(DownloadRequest request){
|
||||
long now = System.currentTimeMillis();
|
||||
if((int)(now - timeForErrorCounter) > TIMEOUT_AFTER_EXCEEDING_LIMIT_ERRORS ) {
|
||||
timeForErrorCounter = now;
|
||||
currentErrors = 0;
|
||||
} else if(currentErrors > TILE_DOWNLOAD_MAX_ERRORS_PER_TIMEOUT){
|
||||
return;
|
||||
}
|
||||
if(request.url == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFileCurrentlyDownloaded(request.fileToSave)) {
|
||||
threadPoolExecutor.execute(new DownloadMapWorker(request));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class DownloadMapWorker implements Runnable, Comparable<DownloadMapWorker> {
|
||||
|
||||
private DownloadRequest request;
|
||||
|
||||
private DownloadMapWorker(DownloadRequest request){
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (request != null && request.fileToSave != null && request.url != null) {
|
||||
if(currentlyDownloaded.contains(request.fileToSave)){
|
||||
return;
|
||||
}
|
||||
|
||||
currentlyDownloaded.add(request.fileToSave);
|
||||
if(log.isDebugEnabled()){
|
||||
log.debug("Start downloading tile : " + request.url); //$NON-NLS-1$
|
||||
}
|
||||
long time = System.currentTimeMillis();
|
||||
try {
|
||||
request.fileToSave.getParentFile().mkdirs();
|
||||
URL url = new URL(request.url);
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setRequestProperty("User-Agent", USER_AGENT); //$NON-NLS-1$
|
||||
connection.setConnectTimeout(35000);
|
||||
BufferedInputStream inputStream = new BufferedInputStream(connection.getInputStream(), 8 * 1024);
|
||||
FileOutputStream stream = null;
|
||||
try {
|
||||
stream = new FileOutputStream(request.fileToSave);
|
||||
Algorithms.streamCopy(inputStream, stream);
|
||||
stream.flush();
|
||||
} finally {
|
||||
Algorithms.closeStream(inputStream);
|
||||
Algorithms.closeStream(stream);
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Downloading tile : " + request.url + " successfull " + (System.currentTimeMillis() - time) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
currentErrors++;
|
||||
request.setError(true);
|
||||
log.error("UnknownHostException, cannot download tile " + request.url + " " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} catch (IOException e) {
|
||||
currentErrors++;
|
||||
request.setError(true);
|
||||
log.warn("Cannot download tile : " + request.url, e); //$NON-NLS-1$
|
||||
} finally {
|
||||
currentlyDownloaded.remove(request.fileToSave);
|
||||
}
|
||||
if (!request.error) {
|
||||
for (IMapDownloaderCallback c : new ArrayList<IMapDownloaderCallback>(callbacks)) {
|
||||
c.tileDownloaded(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DownloadMapWorker o) {
|
||||
return 0; //(int) (time - o.time);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
1214
OsmAnd-java/src/net/osmand/map/OsmandRegionInfo.java
Normal file
1214
OsmAnd-java/src/net/osmand/map/OsmandRegionInfo.java
Normal file
File diff suppressed because it is too large
Load diff
110
OsmAnd-java/src/net/osmand/map/RegionCountry.java
Normal file
110
OsmAnd-java/src/net/osmand/map/RegionCountry.java
Normal file
|
@ -0,0 +1,110 @@
|
|||
package net.osmand.map;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.map.OsmandRegionInfo.OsmAndRegion;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
public class RegionCountry {
|
||||
public String continentName;
|
||||
public TIntArrayList tiles = new TIntArrayList();
|
||||
public int left, right, top, bottom;
|
||||
public String name;
|
||||
public RegionCountry parent;
|
||||
|
||||
private List<RegionCountry> regions = new ArrayList<RegionCountry>();
|
||||
|
||||
public void add(int xdeg, int ydeg) {
|
||||
if (tiles.size() == 0) {
|
||||
left = right = xdeg;
|
||||
top = bottom = ydeg;
|
||||
}
|
||||
left = Math.min(xdeg, left);
|
||||
right = Math.max(xdeg, right);
|
||||
bottom = Math.min(ydeg, bottom);
|
||||
top = Math.max(ydeg, top);
|
||||
tiles.add(xdeg);
|
||||
tiles.add(ydeg);
|
||||
}
|
||||
|
||||
public int getTileSize() {
|
||||
return tiles.size()/2;
|
||||
}
|
||||
|
||||
public int getLon(int i) {
|
||||
return tiles.get(i*2);
|
||||
}
|
||||
|
||||
public int getLat(int i) {
|
||||
return tiles.get(i*2 + 1);
|
||||
}
|
||||
|
||||
public void addSubregion(RegionCountry c) {
|
||||
c.parent = this;
|
||||
regions.add(c);
|
||||
}
|
||||
|
||||
public List<RegionCountry> getSubRegions() {
|
||||
return regions;
|
||||
}
|
||||
|
||||
/*public TLongHashSet calculateTileSet(TLongHashSet t, int z) {
|
||||
for (int j = 0; j < tiles.size(); j++) {
|
||||
int kx = (int) MapUtils.getTileNumberX(z, getLon(j));
|
||||
int ex = (int) MapUtils.getTileNumberX(z, getLon(j) + 0.9999f);
|
||||
int ky = (int) MapUtils.getTileNumberY(z, getLat(j));
|
||||
int ey = (int) MapUtils.getTileNumberY(z, getLat(j) - 0.9999f);
|
||||
for (int x = kx; x <= ex; x++) {
|
||||
for (int y = ky; y <= ey; y++) {
|
||||
long v = (((long) y) << 31) + x;
|
||||
t.add(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}*/
|
||||
|
||||
public static RegionCountry construct(OsmAndRegion reg) {
|
||||
RegionCountry rc = new RegionCountry();
|
||||
if (reg.hasContinentName()) {
|
||||
rc.continentName = reg.getContinentName();
|
||||
}
|
||||
rc.name = reg.getName();
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
for (int i = 0; i < reg.getDegXCount(); i++) {
|
||||
px = reg.getDegX(i) + px;
|
||||
py = reg.getDegY(i) + py;
|
||||
rc.add(px, py);
|
||||
}
|
||||
for (int i = 0; i < reg.getSubregionsCount(); i++) {
|
||||
rc.addSubregion(construct(reg.getSubregions(i)));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
public OsmAndRegion convert() {
|
||||
OsmAndRegion.Builder reg = OsmAndRegion.newBuilder();
|
||||
// System.out.println(r.name + " " + r.tiles.size() + " ?= " + r.calculateTileSet(new TLongHashSet(), 8).size());
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
for (int i = 0; i < this.getTileSize(); i++) {
|
||||
reg.addDegX(this.getLon(i) - px);
|
||||
reg.addDegY(this.getLat(i) - py);
|
||||
px = this.getLon(i);
|
||||
py = this.getLat(i);
|
||||
}
|
||||
String n = Algorithms.capitalizeFirstLetterAndLowercase(this.name.replace('_', ' '));
|
||||
reg.setName(n);
|
||||
if(this.continentName != null) {
|
||||
reg.setContinentName(Algorithms.capitalizeFirstLetterAndLowercase(this.continentName));
|
||||
}
|
||||
for (RegionCountry c : this.regions) {
|
||||
reg.addSubregions(c.convert());
|
||||
}
|
||||
return reg.build();
|
||||
}
|
||||
}
|
44
OsmAnd-java/src/net/osmand/map/RegionRegistry.java
Normal file
44
OsmAnd-java/src/net/osmand/map/RegionRegistry.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
package net.osmand.map;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.map.OsmandRegionInfo.OsmAndRegionInfo;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
public class RegionRegistry {
|
||||
public static final String fileName = "countries.reginfo";
|
||||
private static final Log log = PlatformUtil.getLog(RegionRegistry.class);
|
||||
private static RegionRegistry r = null;
|
||||
|
||||
private List<RegionCountry> countries = new ArrayList<RegionCountry>();
|
||||
|
||||
public static RegionRegistry getRegionRegistry(){
|
||||
if(r == null) {
|
||||
try {
|
||||
long t = -System.currentTimeMillis();
|
||||
r = new RegionRegistry();
|
||||
InputStream in = RegionRegistry.class.getResourceAsStream(RegionRegistry.fileName);
|
||||
OsmAndRegionInfo regInfo = OsmAndRegionInfo.newBuilder().mergeFrom(in).build();
|
||||
for(int j = 0; j < regInfo.getRegionInfo().getRegionsCount(); j++) {
|
||||
r.countries.add(RegionCountry.construct(regInfo.getRegionInfo().getRegions(j)));
|
||||
}
|
||||
t += System.currentTimeMillis();
|
||||
log.info("Initialize regions from file" + t + " ms");
|
||||
} catch (IOException e) {
|
||||
log.error("IO exception reading regions", e);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
public List<RegionCountry> getCountries() {
|
||||
return countries;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue