From 6c02caf0f46b2d56202a2d257267ca57a9f28e1d Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Tue, 17 Jun 2014 23:42:34 +0200 Subject: [PATCH] Parse disruptions of binary trips result (Hafas). --- .../schildbach/pte/AbstractHafasProvider.java | 72 ++++++++++++++++++- .../de/schildbach/pte/util/ParserUtils.java | 54 ++++++++++++++ 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/enabler/src/de/schildbach/pte/AbstractHafasProvider.java b/enabler/src/de/schildbach/pte/AbstractHafasProvider.java index e1372348..6fd881f0 100644 --- a/enabler/src/de/schildbach/pte/AbstractHafasProvider.java +++ b/enabler/src/de/schildbach/pte/AbstractHafasProvider.java @@ -1667,7 +1667,12 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider if (tripDetailsPtr == 0) throw new IllegalStateException("no connection details"); - is.skipBytes(16); + is.skipBytes(4); + + final int disruptionsPtr = is.readIntReverse(); + + is.skipBytes(8); + final Charset stringEncoding = Charset.forName(strings.read(is)); strings.setEncoding(stringEncoding); final String ld = strings.read(is); @@ -1775,6 +1780,14 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider /* final short delay = */is.readShortReverse(); + /* final int legIndex = */is.readShortReverse(); + + is.skipBytes(2); // 0xffff + + /* final int legStatus = */is.readShortReverse(); + + is.skipBytes(2); // 0x0000 + String connectionId = null; if (tripAttrsPtr != 0) { @@ -1888,6 +1901,61 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider final int numStops = is.readShortReverse(); + is.reset(); + is.skipBytes(disruptionsPtr); + + String disruptionText = null; + + if (is.readShortReverse() == 1) + { + is.reset(); + is.skipBytes(disruptionsPtr + 2 + iTrip * 2); + + int disruptionsOffset = is.readShortReverse(); + while (disruptionsOffset != 0) + { + is.reset(); + is.skipBytes(disruptionsPtr + disruptionsOffset); + + strings.read(is); // "0" + + final int disruptionLeg = is.readShortReverse(); + + is.skipBytes(2); // bitmaske + + strings.read(is); // start of line + strings.read(is); // end of line + + strings.read(is); // id + /* final String disruptionTitle = */strings.read(is); + final String disruptionShortText = ParserUtils.formatHtml(strings.read(is)); + + disruptionsOffset = is.readShortReverse(); // next + + if (iLegs == disruptionLeg) + { + final int disruptionAttrsIndex = is.readShortReverse(); + + is.reset(); + is.skipBytes(attrsOffset + disruptionAttrsIndex * 4); + + while (true) + { + final String key = strings.read(is); + if (key == null) + break; + else if (key.equals("Text")) + disruptionText = ParserUtils.resolveEntities(strings.read(is)); + else + is.skipBytes(2); + } + + if (disruptionShortText != null) + disruptionText = disruptionShortText; + } + } + } + List intermediateStops = null; if (numStops > 0) @@ -1997,7 +2065,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider predictedArrivalTime != 0 ? new Date(predictedArrivalTime) : null, plannedArrivalPosition, predictedArrivalPosition, arrivalCancelled); - leg = new Trip.Public(line, direction, departure, arrival, intermediateStops, null, null); + leg = new Trip.Public(line, direction, departure, arrival, intermediateStops, null, disruptionText); } else { diff --git a/enabler/src/de/schildbach/pte/util/ParserUtils.java b/enabler/src/de/schildbach/pte/util/ParserUtils.java index 1a710634..988ae9f5 100644 --- a/enabler/src/de/schildbach/pte/util/ParserUtils.java +++ b/enabler/src/de/schildbach/pte/util/ParserUtils.java @@ -280,6 +280,60 @@ public final class ParserUtils return null; } + private static final Pattern P_HTML_UNORDERED_LIST = Pattern.compile("", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); + private static final Pattern P_HTML_LIST_ITEM = Pattern.compile("
  • (.*?)
  • ", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); + private static final Pattern P_HTML_BREAKS = Pattern.compile("()+", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); + + public static String formatHtml(final CharSequence html) + { + if (html == null) + return null; + + // list item + final StringBuilder builder = new StringBuilder(html.length()); + final Matcher mListItem = P_HTML_LIST_ITEM.matcher(html); + int pListItem = 0; + while (mListItem.find()) + { + builder.append(html.subSequence(pListItem, mListItem.start())); + builder.append("• "); + builder.append(mListItem.group(1)); + builder.append('\n'); + pListItem = mListItem.end(); + } + builder.append(html.subSequence(pListItem, html.length())); + final String html1 = builder.toString(); + + // unordered list + builder.setLength(0); + final Matcher mUnorderedList = P_HTML_UNORDERED_LIST.matcher(html1); + int pUnorderedList = 0; + while (mUnorderedList.find()) + { + builder.append(html1.subSequence(pUnorderedList, mUnorderedList.start())); + builder.append('\n'); + builder.append(mUnorderedList.group(1)); + pUnorderedList = mUnorderedList.end(); + } + builder.append(html1.subSequence(pUnorderedList, html1.length())); + final String html2 = builder.toString(); + + // breaks + builder.setLength(0); + final Matcher mBreaks = P_HTML_BREAKS.matcher(html2); + int pBreaks = 0; + while (mBreaks.find()) + { + builder.append(html2.subSequence(pBreaks, mBreaks.start())); + builder.append(' '); + pBreaks = mBreaks.end(); + } + builder.append(html2.subSequence(pBreaks, html2.length())); + final String html3 = builder.toString(); + + return resolveEntities(html3); + } + private static final Pattern P_ENTITY = Pattern.compile("&(?:#(x[\\da-f]+|\\d+)|(amp|quot|apos|szlig|nbsp));"); public static String resolveEntities(final CharSequence str)