package net.osmand.binary;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntLongHashMap;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import net.osmand.CollatorStringMatcher;
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.Postcode;
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;
// the correct type is -1, this is order in sections for postcode
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 final static List<Integer> TYPES = Arrays.asList(CITY_TOWN_TYPE, POSTCODES_TYPE, VILLAGES_TYPE, STREET_TYPE);
public final static int[] CITY_TYPES = {CITY_TOWN_TYPE, POSTCODES_TYPE, VILLAGES_TYPE};
public static class AddressRegion extends BinaryIndexPart {
String enName;
int indexNameOffset = -1;
List<String> attributeTagsTable = new ArrayList<String>();
List<CitiesBlock> cities = new ArrayList<BinaryMapAddressReaderAdapter.CitiesBlock>();
LatLon calculatedCenter = null;
int bottom31;
int top31;
int right31;
int left31;
public String getEnName() {
return enName;
}
public List<CitiesBlock> getCities() {
return cities;
}
public List<String> getAttributeTagsTable() {
return attributeTagsTable;
}
public int getIndexNameOffset() {
return indexNameOffset;
}
public String getPartName() {
return "Address";
}
public int getFieldNumber() {
return OsmandOdb.OsmAndStructure.ADDRESSINDEX_FIELD_NUMBER;
}
}
public static class CitiesBlock extends BinaryIndexPart {
int type;
public String getPartName() {
return "City";
}
public int getFieldNumber() {
return OsmandOdb.OsmAndAddressIndex.CITIES_FIELD_NUMBER;
}
}
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();
}
private void readBoundariesIndex(AddressRegion 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.left31 = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndTileBox.RIGHT_FIELD_NUMBER:
region.right31 = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndTileBox.TOP_FIELD_NUMBER:
region.top31 = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndTileBox.BOTTOM_FIELD_NUMBER:
region.bottom31 = codedIS.readUInt32();
break;
default:
skipUnknownField(t);
break;
}
}
}
protected void readAddressIndex(AddressRegion region) throws IOException {
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
int length;
int oldLimit;
switch (tag) {
case 0:
if (region.enName == null || region.enName.length() == 0) {
region.enName = region.name == null ? "" : 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.BOUNDARIES_FIELD_NUMBER:
length = codedIS.readRawVarint32();
oldLimit = codedIS.pushLimit(length);
readBoundariesIndex(region);
codedIS.popLimit(oldLimit);
region.enName = codedIS.readString();
break;
case OsmandOdb.OsmAndAddressIndex.ATTRIBUTETAGSTABLE_FIELD_NUMBER:
length = codedIS.readRawVarint32();
oldLimit = codedIS.pushLimit(length);
region.attributeTagsTable = map.readStringTable();
codedIS.popLimit(oldLimit);
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();
length = readInt();
codedIS.seek(region.indexNameOffset + length + 4);
break;
default:
skipUnknownField(t);
break;
}
}
}
protected void readCities(List<City> cities, SearchRequest<City> resultMatcher, StringMatcher matcher,
List<String> additionalTagsTable) 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(new DefaultCityMatcher(matcher), fp, additionalTagsTable);
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, List<String> attributeTagsTable) 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,
attributeTagsTable);
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;
}
}
}
interface CityMatcher {
boolean matches(City city);
}
private class DefaultCityMatcher implements CityMatcher {
private StringMatcher stringMatcher = null;
DefaultCityMatcher(StringMatcher stringMatcher) {
this.stringMatcher = stringMatcher;
}
@Override
public boolean matches(City city) {
if (stringMatcher == null) {
return true;
}
boolean matches = stringMatcher.matches(city.getName());
if (!matches) {
for (String n : city.getAllNames()) {
matches = stringMatcher.matches(n);
if (matches) {
break;
}
}
}
return matches;
}
}
protected City readCityHeader(CityMatcher matcher, int filePointer, List<String> additionalTagsTable) throws IOException {
int x = 0;
int y = 0;
City c = null;
LinkedList<String> additionalTags = null;
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return (matcher == null || matcher.matches(c)) ? c : null;
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());
break;
case OsmandOdb.CityIndex.ATTRIBUTETAGIDS_FIELD_NUMBER:
int tgid = codedIS.readUInt32();
if (additionalTags == null) {
additionalTags = new LinkedList<String>();
}
if (additionalTagsTable != null && tgid < additionalTagsTable.size()) {
additionalTags.add(additionalTagsTable.get(tgid));
}
break;
case OsmandOdb.CityIndex.ATTRIBUTEVALUES_FIELD_NUMBER:
String nm = codedIS.readString();
if (additionalTags != null && additionalTags.size() > 0) {
String tg = additionalTags.pollFirst();
if (tg.startsWith("name:")) {
c.setName(tg.substring("name:".length()), nm);
}
}
break;
case OsmandOdb.CityIndex.NAME_EN_FIELD_NUMBER:
String enName = codedIS.readString();
c.setEnName(enName);
break;
case OsmandOdb.CityIndex.NAME_FIELD_NUMBER:
String name = codedIS.readString();
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));
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,
List<String> additionalTagsTable) throws IOException {
int x = 0;
int y = 0;
LinkedList<String> additionalTags = null;
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));
}
return s;
case OsmandOdb.StreetIndex.ID_FIELD_NUMBER:
s.setId(codedIS.readUInt64());
break;
case OsmandOdb.StreetIndex.ATTRIBUTETAGIDS_FIELD_NUMBER:
int tgid = codedIS.readUInt32();
if (additionalTags == null) {
additionalTags = new LinkedList<String>();
}
if (additionalTagsTable != null && tgid < additionalTagsTable.size()) {
additionalTags.add(additionalTagsTable.get(tgid));
}
break;
case OsmandOdb.StreetIndex.ATTRIBUTEVALUES_FIELD_NUMBER:
String nm = codedIS.readString();
if (additionalTags != null && additionalTags.size() > 0) {
String tg = additionalTags.pollFirst();
if (tg.startsWith("name:")) {
s.setName(tg.substring("name:".length()), nm);
}
}
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, additionalTagsTable);
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, additionalTagsTable);
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, List<String> additionalTagsTable) throws IOException {
int x = 0;
int y = 0;
Street s = new Street(c);
LinkedList<String> additionalTags = null;
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));
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.ATTRIBUTETAGIDS_FIELD_NUMBER:
int tgid = codedIS.readUInt32();
if (additionalTags == null) {
additionalTags = new LinkedList<String>();
}
if (additionalTagsTable != null && tgid < additionalTagsTable.size()) {
additionalTags.add(additionalTagsTable.get(tgid));
}
break;
case OsmandOdb.StreetIntersection.ATTRIBUTEVALUES_FIELD_NUMBER:
String nm = codedIS.readString();
if (additionalTags != null && additionalTags.size() > 0) {
String tg = additionalTags.pollFirst();
if (tg.startsWith("name:")) {
s.setName(tg.substring("name:".length()), nm);
}
}
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, List<String> additionalTagsTable) throws IOException {
int x = 0;
int y = 0;
int x2 = 0;
int y2 = 0;
LinkedList<String> additionalTags = null;
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)));
}
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.ATTRIBUTETAGIDS_FIELD_NUMBER:
int tgid = codedIS.readUInt32();
if (additionalTags == null) {
additionalTags = new LinkedList<String>();
}
if (additionalTagsTable != null && tgid < additionalTagsTable.size()) {
additionalTags.add(additionalTagsTable.get(tgid));
}
break;
case OsmandOdb.BuildingIndex.ATTRIBUTEVALUES_FIELD_NUMBER:
String nm = codedIS.readString();
if (additionalTags != null && additionalTags.size() > 0) {
String tg = additionalTags.pollFirst();
if (tg.startsWith("name:")) {
b.setName(tg.substring("name:".length()), nm);
}
}
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, List<Integer> typeFilter) throws IOException {
TIntArrayList loffsets = new TIntArrayList();
CollatorStringMatcher stringMatcher = new CollatorStringMatcher(req.nameQuery, req.matcherMode);
String postcode = Postcode.normalize(req.nameQuery, map.getCountryName());
final CityMatcher postcodeMatcher = new DefaultCityMatcher(new CollatorStringMatcher(postcode, req.matcherMode));
final CityMatcher cityMatcher = new DefaultCityMatcher(stringMatcher);
final CityMatcher cityPostcodeMatcher = new CityMatcher() {
@Override
public boolean matches(City city) {
return city.isPostcode() ? postcodeMatcher.matches(city) : cityMatcher.matches(city);
}
};
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(stringMatcher.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];
TIntArrayList[] refsContainer = new TIntArrayList[5];
for (int i = 0; i < refs.length; i++) {
refs[i] = new TIntArrayList();
refsContainer[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, refsContainer, fp);
codedIS.popLimit(soldLim);
} else if (stag != 0) {
skipUnknownField(st);
}
} while (stag != 0);
codedIS.popLimit(oldLim);
if (req.isCancelled()) {
return;
}
}
if (typeFilter == null) {
typeFilter = TYPES;
}
for (int i = 0; i < typeFilter.size() && !req.isCancelled(); i++) {
TIntArrayList list = refs[typeFilter.get(i)];
TIntArrayList listContainer = refsContainer[typeFilter.get(i)];
if (typeFilter.get(i) == STREET_TYPE) {
TIntLongHashMap mp = new TIntLongHashMap();
for (int j = 0; j < list.size(); j++) {
mp.put(list.get(j), listContainer.get(j));
}
list.sort();
for (int j = 0; j < list.size() && !req.isCancelled(); j ++) {
int offset = list.get(j);
if (j > 0 && offset == list.get(j - 1)) {
continue;
}
City obj;
{
int contOffset = (int) mp.get(offset);
codedIS.seek(contOffset);
int len = codedIS.readRawVarint32();
int old = codedIS.pushLimit(len);
obj = readCityHeader(null, contOffset, reg.attributeTagsTable);
codedIS.popLimit(old);
}
if (obj != null) {
codedIS.seek(offset);
int len = codedIS.readRawVarint32();
int old = codedIS.pushLimit(len);
LatLon l = obj.getLocation();
Street s = new Street(obj);
s.setFileOffset(offset);
readStreet(s, null, false, MapUtils.get31TileNumberX(l.getLongitude()) >> 7,
MapUtils.get31TileNumberY(l.getLatitude()) >> 7, obj.isPostcode() ? obj.getName() : null,
reg.attributeTagsTable);
boolean matches = stringMatcher.matches(s.getName());
if (!matches) {
for (String n : s.getAllNames()) {
matches = stringMatcher.matches(n);
if (matches) {
break;
}
}
}
if (matches) {
req.publish(s);
}
codedIS.popLimit(old);
}
}
} else {
list.sort();
TIntSet published = new TIntHashSet();
for (int j = 0; j < list.size() && !req.isCancelled(); j++) {
int offset = list.get(j);
if (j > 0 && offset == list.get(j - 1)) {
continue;
}
codedIS.seek(offset);
int len = codedIS.readRawVarint32();
int old = codedIS.pushLimit(len);
City obj = readCityHeader(cityPostcodeMatcher, list.get(j), reg.attributeTagsTable);
if (obj != null && !published.contains(offset)) {
req.publish(obj);
published.add(offset);
}
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,
TIntArrayList[] refsContainer, int fp) throws IOException {
TIntArrayList toAdd = null;
TIntArrayList toAddCity = null;
int shiftindex = 0;
int shiftcityindex = 0;
boolean add = true;
while (true) {
if (req.isCancelled()) {
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
if(tag == 0 || tag == AddressNameIndexDataAtom.SHIFTTOINDEX_FIELD_NUMBER) {
if (toAdd != null && add) {
if(shiftindex != 0) {
toAdd.add(shiftindex);
}
if(shiftcityindex != 0) {
toAddCity.add(shiftcityindex);
}
}
}
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 (toAddCity != null) {
shiftcityindex = fp - codedIS.readInt32();
}
break;
case AddressNameIndexDataAtom.XY16_FIELD_NUMBER:
int in32 = codedIS.readInt32();
int x16 = (in32 >>> 16) << 15;
int y16 = (in32 & ((1 << 16) - 1)) << 15;
add = !req.isBboxSpecified() || req.contains(x16, y16, x16, y16);
break;
case AddressNameIndexDataAtom.SHIFTTOINDEX_FIELD_NUMBER:
shiftindex = fp - codedIS.readInt32();
break;
case AddressNameIndexDataAtom.TYPE_FIELD_NUMBER:
int type = codedIS.readInt32();
toAdd = refs[type];
toAddCity = refsContainer[type];
break;
default:
skipUnknownField(t);
break;
}
}
}
}