001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io.ozi; 003 004import java.io.BufferedReader; 005import java.io.IOException; 006import java.io.InputStream; 007import java.io.InputStreamReader; 008import java.nio.charset.StandardCharsets; 009import java.util.ArrayList; 010import java.util.Collection; 011import java.util.Collections; 012import java.util.Objects; 013 014import org.openstreetmap.josm.data.SystemOfMeasurement; 015import org.openstreetmap.josm.data.coor.LatLon; 016import org.openstreetmap.josm.data.gpx.GpxConstants; 017import org.openstreetmap.josm.data.gpx.GpxData; 018import org.openstreetmap.josm.data.gpx.GpxTrack; 019import org.openstreetmap.josm.data.gpx.WayPoint; 020import org.openstreetmap.josm.io.IGpxReader; 021import org.openstreetmap.josm.tools.Logging; 022import org.xml.sax.SAXException; 023 024/** 025 * Reads an OziExplorer Waypoint file. Based on information from 026 * <a href="https://www.oziexplorer4.com/eng/help/fileformats.html">https://www.oziexplorer4.com</a>. 027 * @since 18179 028 */ 029public class OziWptReader implements IGpxReader { 030 031 private static final int IDX_NAME = 1; 032 private static final int IDX_LAT = 2; 033 private static final int IDX_LON = 3; 034 private static final int IDX_DESC = 10; 035 private static final int IDX_ELE = 14; 036 037 private static final int INVALID_ELE = -777; 038 039 private final InputStream source; 040 private GpxData data; 041 private int success; // number of successfully parsed lines 042 043 /** 044 * Constructs a new {@code OziWptReader} 045 * @param source Ozi wpt file input stream 046 * @throws IOException if an I/O error occurs 047 */ 048 public OziWptReader(InputStream source) throws IOException { 049 this.source = Objects.requireNonNull(source); 050 } 051 052 @Override 053 public boolean parse(boolean tryToFinish) throws SAXException, IOException { 054 data = new GpxData(); 055 Collection<Collection<WayPoint>> currentTrack = new ArrayList<>(); 056 Collection<WayPoint> waypoints = new ArrayList<>(); 057 try (BufferedReader rd = new BufferedReader(new InputStreamReader(source, StandardCharsets.UTF_8))) { 058 int linecount = 0; 059 String line; 060 do { 061 line = rd.readLine(); 062 if (line != null) { 063 linecount++; 064 if (linecount == 1) { 065 if (!line.startsWith("OziExplorer Waypoint File")) { 066 throw new UnsupportedOperationException("Unsupported format: " + line); 067 } 068 } else if (linecount == 2) { 069 if (!"WGS 84".equals(line)) { 070 throw new UnsupportedOperationException("Unsupported datum: " + line); 071 } 072 } else if (linecount == 3 || linecount == 4) { 073 Logging.trace(line); 074 } else { 075 try { 076 String[] fields = line.split(","); 077 WayPoint currentwp = new WayPoint(new LatLon( 078 Double.parseDouble(fields[IDX_LAT]), 079 Double.parseDouble(fields[IDX_LON]))); 080 currentwp.put(GpxConstants.GPX_NAME, fields[IDX_NAME]); 081 currentwp.put(GpxConstants.GPX_DESC, fields[IDX_DESC]); 082 String ele = fields[IDX_ELE]; 083 if (!ele.isEmpty()) { 084 int eleInFeet = Integer.parseInt(ele); 085 if (eleInFeet != 0 && eleInFeet != INVALID_ELE) { 086 currentwp.put(GpxConstants.PT_ELE, eleInFeet * SystemOfMeasurement.IMPERIAL.aValue); 087 } 088 } 089 waypoints.add(currentwp); 090 success++; 091 } catch (IllegalArgumentException e) { 092 Logging.error(e); 093 } 094 } 095 } 096 } while (line != null); 097 } 098 currentTrack.add(waypoints); 099 data.tracks.add(new GpxTrack(currentTrack, Collections.<String, Object>emptyMap())); 100 return true; 101 } 102 103 @Override 104 public GpxData getGpxData() { 105 return data; 106 } 107 108 @Override 109 public int getNumberOfCoordinates() { 110 return success; 111 } 112}