Changeset 14067 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2018-07-30T21:57:20+02:00 (6 years ago)
Author:
Don-vip
Message:

fix #16496 - fix invalid parsing of NMEA time (decimal-fraction of seconds)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java

    r14010 r14067  
    1515import java.util.Locale;
    1616import java.util.Objects;
    17 import java.util.Optional;
     17import java.util.regex.Matcher;
     18import java.util.regex.Pattern;
    1819
    1920import org.openstreetmap.josm.data.coor.LatLon;
     
    4546public class NmeaReader implements IGpxReader {
    4647
     48    /**
     49     * Course Over Ground and Ground Speed.
     50     * <p>
     51     * The actual course and speed relative to the ground
     52     */
    4753    enum VTG {
    4854        COURSE(1), COURSE_REF(2), // true course
     
    5965    }
    6066
     67    /**
     68     * Recommended Minimum Specific GNSS Data.
     69     * <p>
     70     * Time, date, position, course and speed data provided by a GNSS navigation receiver.
     71     * This sentence is transmitted at intervals not exceeding 2-seconds.
     72     * RMC is the recommended minimum data to be provided by a GNSS receiver.
     73     * All data fields must be provided, null fields used only when data is temporarily unavailable.
     74     */
    6175    enum RMC {
    6276        TIME(1),
     
    8195    }
    8296
     97    /**
     98     * Global Positioning System Fix Data.
     99     * <p>
     100     * Time, position and fix related data for a GPS receiver.
     101     */
    83102    enum GGA {
    84103        TIME(1), LATITUDE(2), LATITUDE_NAME(3), LONGITUDE(4), LONGITUDE_NAME(5),
     
    99118    }
    100119
     120    /**
     121     * GNSS DOP and Active Satellites.
     122     * <p>
     123     * GNSS receiver operating mode, satellites used in the navigation solution reported by the GGA or GNS sentence,
     124     * and DOP values.
     125     * If only GPS, GLONASS, etc. is used for the reported position solution the talker ID is GP, GL, etc.
     126     * and the DOP values pertain to the individual system. If GPS, GLONASS, etc. are combined to obtain the
     127     * reported position solution multiple GSA sentences are produced, one with the GPS satellites, another with
     128     * the GLONASS satellites, etc. Each of these GSA sentences shall have talker ID GN, to indicate that the
     129     * satellites are used in a combined solution and each shall have the PDOP, HDOP and VDOP for the
     130     * combined satellites used in the position.
     131     */
    101132    enum GSA {
    102133        AUTOMATIC(1),
     
    115146    }
    116147
     148    /**
     149     * Geographic Position - Latitude/Longitude.
     150     * <p>
     151     * Latitude and Longitude of vessel position, time of position fix and status.
     152     */
    117153    enum GLL {
    118154        LATITUDE(1), LATITUDE_NS(2), // Latitude, NS
     
    135171    GpxData data;
    136172
     173    private static final Pattern DATE_TIME_PATTERN = Pattern.compile("(\\d{12})(\\.\\d+)?");
     174
    137175    private final SimpleDateFormat rmcTimeFmt = new SimpleDateFormat("ddMMyyHHmmss.SSS", Locale.ENGLISH);
    138     private final SimpleDateFormat rmcTimeFmtStd = new SimpleDateFormat("ddMMyyHHmmss", Locale.ENGLISH);
    139176
    140177    private Date readTime(String p) throws IllegalDataException {
    141         Date d = Optional.ofNullable(rmcTimeFmt.parse(p, new ParsePosition(0)))
    142                 .orElseGet(() -> rmcTimeFmtStd.parse(p, new ParsePosition(0)));
    143         if (d == null)
    144             throw new IllegalDataException("Date is malformed: '" + p + "'");
    145         return d;
     178        // NMEA defines time with "a variable number of digits for decimal-fraction of seconds"
     179        // This variable decimal fraction cannot be parsed by SimpleDateFormat
     180        Matcher m = DATE_TIME_PATTERN.matcher(p);
     181        if (m.matches()) {
     182            String date = m.group(1);
     183            double milliseconds = 0d;
     184            if (m.groupCount() > 1 && m.group(2) != null) {
     185                milliseconds = 1000d * Double.parseDouble("0" + m.group(2));
     186            }
     187            // Add milliseconds on three digits to match SimpleDateFormat pattern
     188            date += String.format(".%03d", (int) milliseconds);
     189            Date d = rmcTimeFmt.parse(date, new ParsePosition(0));
     190            if (d != null)
     191                return d;
     192        }
     193        throw new IllegalDataException("Date is malformed: '" + p + "'");
    146194    }
    147195
     
    177225        this.source = Objects.requireNonNull(source);
    178226        rmcTimeFmt.setTimeZone(DateUtils.UTC);
    179         rmcTimeFmtStd.setTimeZone(DateUtils.UTC);
    180227    }
    181228
Note: See TracChangeset for help on using the changeset viewer.