/* This file is part of RouteConverter. RouteConverter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. RouteConverter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RouteConverter; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (C) 2007 Christian Pesch. All Rights Reserved. */ package slash.navigation.base; import slash.navigation.common.NavigationPosition; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static java.net.URLEncoder.encode; import static slash.common.io.Transfer.UTF8_ENCODING; import static slash.navigation.base.RouteCharacteristics.Route; /** * The base of all URL parsing navigation formats. * * @author Christian Pesch */ public abstract class BaseUrlParsingFormat extends BaseUrlFormat { @SuppressWarnings({"unchecked"}) public <P extends NavigationPosition> Wgs84Route createRoute(RouteCharacteristics characteristics, String name, List<P> positions) { return new Wgs84Route(this, characteristics, (List<Wgs84Position>) positions); } protected void processURL(String url, String encoding, ParserContext<Wgs84Route> context) { Map<String, List<String>> parameters = parseURLParameters(url, encoding); if (parameters == null) return; List<Wgs84Position> positions = parsePositions(parameters); if (positions.size() > 0) context.appendRoute(createRoute(Route, null, positions)); } protected abstract List<Wgs84Position> parsePositions(Map<String, List<String>> parameters); public/*for tests*/ Map<String, List<String>> parseURLParameters(String data, String encoding) { if (data == null || data.length() == 0) return null; try { byte[] bytes = data.getBytes(encoding); return parseParameters(bytes, encoding); } catch (UnsupportedEncodingException e) { return null; } } private byte convertHexDigit(byte b) { if ((b >= '0') && (b <= '9')) return (byte) (b - '0'); if ((b >= 'a') && (b <= 'f')) return (byte) (b - 'a' + 10); if ((b >= 'A') && (b <= 'F')) return (byte) (b - 'A' + 10); return 0; } private void putMapEntry(Map<String, List<String>> map, String name, String value) { List<String> values = map.get(name); if (values == null) { values = new ArrayList<>(1); map.put(name, values); } values.add(value); } private Map<String, List<String>> parseParameters(byte[] data, String encoding) throws UnsupportedEncodingException { if (data == null || data.length == 0) return null; Map<String, List<String>> result = new HashMap<>(); int ix = 0; int ox = 0; String key = null; String value; while (ix < data.length) { byte c = data[ix++]; switch ((char) c) { case '&': value = new String(data, 0, ox, encoding); if (key != null) { putMapEntry(result, key, value); key = null; } ox = 0; break; case '=': if (key == null) { key = new String(data, 0, ox, encoding); ox = 0; } else { data[ox++] = c; } break; case '+': data[ox++] = (byte) ' '; break; case '%': int leftNibble = convertHexDigit(data[ix++]) << 4; byte rightNibble = ix < data.length ? convertHexDigit(data[ix++]) : 0; data[ox++] = (byte) (leftNibble + rightNibble); break; case '?': break; default: data[ox++] = c; } } // The last value does not end in '&'. So save it now. if (key != null) { value = new String(data, 0, ox, encoding); putMapEntry(result, key, value); } return result; } protected String decodeDescription(String description) { if (description == null) return ""; try { return URLDecoder.decode(description, UTF8_ENCODING); } catch (UnsupportedEncodingException e) { return description; } } protected String encodeDescription(String description) { if (description == null) return ""; try { description = encode(description, UTF8_ENCODING); description = description.replace("%2C", ","); return description; } catch (UnsupportedEncodingException e) { return description; } } }