commit 3d0f057e3aa3120b0ce903d38e311d93290a0a2f
parent 776a0f1ec3dead7a3fb44e660ea873f36be816e4
Author: Sergej Orlov <wladimirych@gmail.com>
Date: Fri, 23 Nov 2018 21:36:33 +0100
[tracks] rafctor loading: split format parsers to files
Diffstat:
9 files changed, 622 insertions(+), 593 deletions(-)
diff --git a/src/lib/leaflet.control.track-list/lib/geo_file_formats.js b/src/lib/leaflet.control.track-list/lib/geo_file_formats.js
@@ -1,599 +1,16 @@
-import JSUnzip from 'vendored/github.com/augustl/js-unzip/js-unzip';
-import tynyInflate from 'tiny-inflate';
-import stripBom from 'lib/stripBom';
-
-import {decode as utf8_decode} from 'utf8';
import {fetch} from 'lib/xhr-promise';
import urlViaCorsProxy from 'lib/CORSProxy';
import {isGpsiesUrl, gpsiesRequestOptions, gpsiesParser} from './gpsies';
import {isGpslibUrl, gpslibRequestOptions, gpslibParser} from './gpslib';
import {isStravaUrl, stravaRequestOptions, stravaParser} from './strava';
import {isEndomondoUrl, endomondoRequestOptions, endomondoParser} from './endomondo';
-import {parseTrackUrlData, parseNakarteUrl, isNakarteLinkUrl, nakarteLinkRequestOptions, nakarteLinkParser} from './nktk';
+import {parseTrackUrl, parseNakarteUrl, isNakarteLinkUrl, nakarteLinkRequestOptions, nakarteLinkParser} from './nktk';
import {stringToArrayBuffer, arrayBufferToString} from 'lib/binary-strings';
-
-function xmlGetNodeText(node) {
- if (node) {
- return Array.prototype.slice.call(node.childNodes)
- .map(function(node) {
- return node.nodeValue;
- }
- )
- .join('');
- }
-}
-
-
-function inflate(compressed, originalSize) {
- if (originalSize === 0) {
- return '';
- }
- const out = new Uint8Array(originalSize);
- tynyInflate(new Uint8Array(stringToArrayBuffer(compressed)), out);
- return arrayBufferToString(out);
-}
-
-function parseGpx(txt, name, preferNameFromFile) {
- var error;
-
- function getSegmentPoints(segment_element) {
- var points_elements = segment_element.getElementsByTagName('trkpt');
- var points = [];
- for (var i = 0; i < points_elements.length; i++) {
- var point_element = points_elements[i];
- var lat = parseFloat(point_element.getAttribute('lat'));
- var lng = parseFloat(point_element.getAttribute('lon'));
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- points.push({lat: lat, lng: lng});
- }
- return points;
- }
-
- var getTrackSegments = function(xml) {
- var segments = [];
- var segments_elements = xml.getElementsByTagName('trkseg');
- for (var i = 0; i < segments_elements.length; i++) {
- var segment_points = getSegmentPoints(segments_elements[i]);
- if (segment_points.length) {
- segments.push(segment_points);
- }
- }
- return segments;
- };
-
- function getRoutePoints(rte_element) {
- var points_elements = rte_element.getElementsByTagName('rtept');
- var points = [];
- for (var i = 0; i < points_elements.length; i++) {
- var point_element = points_elements[i];
- var lat = parseFloat(point_element.getAttribute('lat'));
- var lng = parseFloat(point_element.getAttribute('lon'));
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- points.push({lat: lat, lng: lng});
- }
- return points;
- }
-
- var getRoutes = function(xml) {
- var routes = [];
- var rte_elements = xml.getElementsByTagName('rte');
- for (var i = 0; i < rte_elements.length; i++) {
- var rte_points = getRoutePoints(rte_elements[i]);
- if (rte_points.length) {
- routes.push(rte_points);
- }
- }
- return routes;
- };
-
- var getWaypoints = function(xml) {
- var waypoint_elements = xml.getElementsByTagName('wpt');
- var waypoints = [];
- for (var i = 0; i < waypoint_elements.length; i++) {
- var waypoint_element = waypoint_elements[i];
- var waypoint = {};
- waypoint.lat = parseFloat(waypoint_element.getAttribute('lat'));
- waypoint.lng = parseFloat(waypoint_element.getAttribute('lon'));
- if (isNaN(waypoint.lat) || isNaN(waypoint.lng)) {
- error = 'CORRUPT';
- continue;
- }
- let wptName = xmlGetNodeText(waypoint_element.getElementsByTagName('name')[0]) || '';
- try {
- wptName = utf8_decode((wptName));
- } catch (e) {
- error = 'CORRUPT';
- wptName = '__invalid point name__';
- }
- waypoint.name = wptName;
- waypoint.symbol_name = xmlGetNodeText(waypoint_element.getElementsByTagName('sym')[0]);
- waypoints.push(waypoint);
- }
- return waypoints;
- };
-
- txt = stripBom(txt);
- // remove namespaces
- txt = txt.replace(/<([^ >]+):([^ >]+)/g, '<$1_$2');
- try {
- var dom = (new DOMParser()).parseFromString(txt, "text/xml");
- } catch (e) {
- return null;
- }
- if (dom.documentElement.nodeName === 'parsererror') {
- return null;
- }
- if (dom.getElementsByTagName('gpx').length === 0) {
- return null;
- }
- if (preferNameFromFile) {
- for (let trk of [...dom.getElementsByTagName('trk')]) {
- let trkName = trk.getElementsByTagName('name')[0];
- if (trkName) {
- try {
- trkName = utf8_decode(xmlGetNodeText(trkName));
- } catch (e) {
- error = 'CORRUPT';
- }
- if (trkName.length) {
- name = trkName;
- break;
- }
- }
- }
- }
- return [{
- name: name,
- tracks: getTrackSegments(dom).concat(getRoutes(dom)),
- points: getWaypoints(dom),
- error: error
- }];
-}
-
-
-function parseOziRte(txt, name) {
- let error, segments = [];
- txt = stripBom(txt);
- const lines = txt.split('\n');
- if (lines[0].indexOf('OziExplorer Route File') !== 0) {
- return null;
- }
- let currentSegment = [];
- for (let i=4; i < lines.length; i++) {
- let line = lines[i].trim();
- if (!line) {
- continue;
- }
- let fields = line.split(',');
- if (fields[0] === 'R') {
- if (currentSegment.length) {
- segments.push(currentSegment);
- }
- currentSegment = [];
- } else if (fields[0] === 'W') {
- let lat = parseFloat(fields[5]);
- let lng = parseFloat(fields[6]);
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- currentSegment.push({lat, lng});
- } else {
- error = 'CORRUPT';
- break
- }
- }
- if (currentSegment.length) {
- segments.push(currentSegment);
- }
- return [{name, tracks: segments, error}];
-}
-
-function parseOziPlt(txt, name) {
- var error;
- var segments = [];
- txt = stripBom(txt);
- var lines = txt.split('\n');
- if (lines[0].indexOf('OziExplorer Track Point File') !== 0) {
- return null;
- }
- var expected_points_num = parseInt(lines[5], 10);
- var current_segment = [];
- var total_points_num = 0;
- for (var i = 6; i < lines.length; i++) {
- var line = lines[i].trim();
- if (!line) {
- continue;
- }
- var fields = line.split(',');
- var lat = parseFloat(fields[0]);
- var lon = parseFloat(fields[1]);
- var is_start_of_segment = parseInt(fields[2], 10);
- if (isNaN(lat) || isNaN(lon) || isNaN(is_start_of_segment)) {
- error = 'CORRUPT';
- break;
- }
- if (is_start_of_segment) {
- current_segment = [];
- }
- if (!current_segment.length) {
- segments.push(current_segment);
- }
- current_segment.push({lat: lat, lng: lon});
- total_points_num += 1;
- }
- if (isNaN(expected_points_num) || (expected_points_num !== 0 && expected_points_num !== total_points_num)) {
- error = 'CORRUPT';
- }
- return [{name: name, tracks: segments, error: error}];
-}
-
-function decodeCP1251(s) {
- var c, i, s2 = [];
- for (i = 0; i < s.length; i++) {
- c = s.charCodeAt(i);
- if (c >= 192 && c <= 255) {
- c += (0x410 - 192);
- } else if (c === 168) {
- c = 0x0401;
- } else if (c === 184) {
- c = 0x0451;
- }
- s2.push(String.fromCharCode(c));
- }
- return s2.join('');
-}
-
-function decode866(s) {
- var c, i, s2 = [];
- for (i = 0; i < s.length; i++) {
- c = s.charCodeAt(i);
- if (c >= 128 && c <= 175) {
- c += (0x410 - 128);
- } else if (c >= 224 && c <= 239) {
- c += (0x440 - 224);
- } else if (c === 240) {
- c = 0x0401;
- } else if (c === 241) {
- c = 0x0451;
- }
- s2.push(String.fromCharCode(c));
- }
- return s2.join('');
-}
-
-function parseOziWpt(txt, name) {
- var points = [],
- error,
- lines, line,
- i,
- lat, lng, pointName, fields;
- txt = stripBom(txt);
- lines = txt.split('\n');
- if (lines[0].indexOf('OziExplorer Waypoint File') !== 0) {
- return null;
- }
- for (i = 4; i < lines.length; i++) {
- line = lines[i].trim();
- if (!line) {
- continue;
- }
- fields = line.split(',');
- lat = parseFloat(fields[2]);
- lng = parseFloat(fields[3]);
- pointName = decodeCP1251(fields[1]).trim();
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- points.push({
- lat: lat,
- lng: lng,
- name: pointName
- }
- );
- }
- return [{name: name, points: points, error: error}];
-}
-
-function parseKml(txt, name) {
- var error;
- var getSegmentPoints = function(coordinates_element) {
- // convert multiline text value of tag to single line
- var coordinates_string = xmlGetNodeText(coordinates_element);
- var points_strings = coordinates_string.split(/\s+/);
- var points = [];
- for (var i = 0; i < points_strings.length; i++) {
- if (points_strings[i].length) {
- var point = points_strings[i].split(',');
- var lat = parseFloat(point[1]);
- var lng = parseFloat(point[0]);
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- points.push({lat: lat, lng: lng});
- }
- }
- return points;
- };
-
- var getTrackSegments = function(xml) {
- var segments_elements = xml.getElementsByTagName('LineString');
- var segments = [];
- for (var i = 0; i < segments_elements.length; i++) {
- var coordinates_element = segments_elements[i].getElementsByTagName('coordinates');
- if (coordinates_element.length) {
- var segment_points = getSegmentPoints(coordinates_element[0]);
- if (segment_points.length) {
- segments.push(segment_points);
- }
- }
- }
- return segments;
- };
-
- function getPoints(dom) {
- var points = [],
- placemarks, i, coord, name, lat, lng, pointObjs;
- placemarks = dom.getElementsByTagName('Placemark');
- for (i = 0; i < placemarks.length; i++) {
- pointObjs = placemarks[i].getElementsByTagName('Point');
- if (pointObjs.length === 0) {
- continue
- } else if (pointObjs.length > 1) {
- error = 'CORRUPT';
- break;
- }
- coord = pointObjs[0].getElementsByTagName('coordinates');
- if (coord.length !== 1) {
- error = 'CORRUPT';
- break;
- }
- coord = xmlGetNodeText(coord[0]);
- coord = coord.split(',');
- lat = parseFloat(coord[1]);
- lng = parseFloat(coord[0]);
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- name = placemarks[i].getElementsByTagName('name');
- if (name.length !== 1) {
- error = 'CORRUPT';
- break;
- }
- try {
- name = utf8_decode(xmlGetNodeText(name[0])).trim();
- } catch (e) {
- error = 'CORRUPT';
- break;
- }
- points.push({
- name: name,
- lat: lat,
- lng: lng
- }
- );
- }
- return points;
- }
-
- txt = stripBom(txt);
- txt = txt.replace(/<([^ >]+):([^ >]+)/g, '<$1_$2');
- try {
- var dom = (new DOMParser()).parseFromString(txt, "text/xml");
- } catch (e) {
- return null;
- }
- if (dom.documentElement.nodeName === 'parsererror') {
- return null;
- }
- if (dom.getElementsByTagName('kml').length === 0) {
- return null;
- }
-
- return [{name: name, tracks: getTrackSegments(dom), points: getPoints(dom), error: error}];
-}
-
-function parseKmz(txt, name) {
- var uncompressed;
- try {
- var unzipper = new JSUnzip(txt);
- } catch (e) {
- return null;
- }
- var tracks = [],
- points = [],
- geodata,
- error;
- var hasDocKml = false;
- if (!unzipper.isZipFile()) {
- return null;
- }
- try {
- unzipper.readEntries();
- } catch (e) {
- return null;
- }
- var i, entry;
- for (i = 0; i < unzipper.entries.length; i++) {
- entry = unzipper.entries[i];
- if (entry.fileName === 'doc.kml') {
- hasDocKml = true;
- break;
- }
- }
- if (!hasDocKml) {
- return null;
- }
-
- for (i = 0; i < unzipper.entries.length; i++) {
- entry = unzipper.entries[i];
- if (entry.fileName.match(/\.kml$/i)) {
- if (entry.compressionMethod === 0) {
- uncompressed = entry.data;
- } else if (entry.compressionMethod === 8) {
- uncompressed = inflate(entry.data, entry.uncompressedSize);
- } else {
- return null;
- }
- geodata = parseKml(uncompressed, 'dummmy');
- if (geodata) {
- error = error || geodata[0].error;
- tracks.push.apply(tracks, geodata[0].tracks);
- points.push.apply(points, geodata[0].points);
- }
- }
- }
-
- geodata = [{name: name, error: error, tracks: tracks, points: points}];
- return geodata;
-}
-
-function parseYandexRulerString(s) {
- var last_lat = 0;
- var last_lng = 0;
- var error;
- var points = [];
- s = s.replace(/%2C/ig, ',');
- var points_str = s.split('~');
- for (var i = 0; i < points_str.length; i++) {
- var point = points_str[i].split(',');
- var lng = parseFloat(point[0]);
- var lat = parseFloat(point[1]);
- if (isNaN(lat) || isNaN(lng)) {
- error = 'CORRUPT';
- break;
- }
- last_lng += lng;
- last_lat += lat;
- points.push({lat: last_lat, lng: last_lng});
- }
- return {error: error, points: points};
-}
-
-
-function parseYandexRulerUrl(s) {
- var re = /yandex\..+[?&]rl=([^&]+)/;
- var m = re.exec(s);
- if (!m) {
- return null;
- }
- var res = parseYandexRulerString(m[1]);
- return [{name: 'Yandex ruler', error: res.error, tracks: [res.points]}];
-}
-
-
-function parseZip(txt, name) {
- try {
- var unzipper = new JSUnzip(txt);
- } catch (e) {
- return null;
- }
- if (!unzipper.isZipFile()) {
- return null;
- }
- try {
- unzipper.readEntries();
- } catch (e) {
- return null;
- }
- var geodata_array = [];
- for (var i = 0; i < unzipper.entries.length; i++) {
- var entry = unzipper.entries[i];
- var uncompressed;
- if (entry.compressionMethod === 0) {
- uncompressed = entry.data;
- } else if (entry.compressionMethod === 8) {
- uncompressed = inflate(entry.data, entry.uncompressedSize);
- } else {
- return null;
- }
- var file_name = decode866(entry.fileName);
- var geodata = parseGeoFile(file_name, uncompressed);
- for (let item of geodata) {
- if (item.error === 'UNSUPPORTED' && item.name.match(/\.pdf$|\.doc$|\.txt$\.jpg$/)) {
- continue;
- }
- geodata_array.push(item)
- }
- }
- return geodata_array;
-}
-
-// function parseYandexMap(txt) {
-// var start_tag = '<script id="vpage" type="application/json">';
-// var json_start = txt.indexOf(start_tag);
-// if (json_start === -1) {
-// return null;
-// }
-// json_start += start_tag.length;
-// var json_end = txt.indexOf('</script>', json_start);
-// if (json_end === -1) {
-// return null;
-// }
-// var map_data = txt.substring(json_start, json_end);
-// map_data = JSON.parse(map_data);
-// console.log(map_data);
-// if (!('request' in map_data)) {
-// return null;
-// }
-// var name = 'YandexMap';
-// var segments = [];
-// var error;
-// if (map_data.vpage && map_data.vpage.data && map_data.vpage.data.objects && map_data.vpage.data.objects.length) {
-// var mapName = ('' + (map_data.vpage.data.name || '')).trim();
-// if (mapName.length > 3) {
-// name = '';
-// } else if (mapName.length) {
-// name += ': ';
-// }
-// name += fileutils.decodeUTF8(mapName);
-// map_data.vpage.data.objects.forEach(function(obj){
-// if (obj.pts && obj.pts.length) {
-// var segment = [];
-// for (var i=0; i< obj.pts.length; i++) {
-// var pt = obj.pts[i];
-// var lng = parseFloat(pt[0]);
-// var lat = parseFloat(pt[1]);
-// if (isNaN(lat) || isNaN(lng)) {
-// error = 'CORRUPT';
-// break;
-// }
-// segment.push({lat: lat, lng:lng});
-// }
-// if (segment.length) {
-// segments.push(segment);
-// }
-// }
-// });
-// }
-// if (map_data.request.args && map_data.request.args.rl) {
-// var res = parseYandexRulerString(map_data.request.args.rl);
-// error = error || res.error;
-// if (res.points && res.points.length) {
-// segments.push(res.points);
-// }
-// }
-// return [{name: name, error: error, tracks: segments}];
-// }
-
-
-function parseTrackUrl(s) {
- var i = s.indexOf('track://');
- if (i === -1) {
- return null;
- }
- return parseTrackUrlData(s.substring(i + 8));
-}
-
+import parseGpx from './gpx';
+import {parseKmz, parseKml} from './kml';
+import parseZip from './zip';
+import {parseYandexRulerUrl} from './yandex';
+import {parseOziPlt, parseOziRte, parseOziWpt} from './ozi';
function simpleRequestOptions(url) {
const requestOptions = [{
@@ -603,7 +20,6 @@ function simpleRequestOptions(url) {
return {requestOptions};
}
-
function simpleTrackParser(name, responses) {
if (responses.length !== 1) {
throw new Error(`Invalid responses array length ${responses.length}`);
@@ -611,7 +27,6 @@ function simpleTrackParser(name, responses) {
return parseGeoFile(name, responses[0].responseBinaryText);
}
-
async function loadFromUrl(url) {
let geodata;
geodata = parseGeoFile('', url);
diff --git a/src/lib/leaflet.control.track-list/lib/gpx.js b/src/lib/leaflet.control.track-list/lib/gpx.js
@@ -0,0 +1,128 @@
+import {decode as utf8_decode} from 'utf8';
+import {xmlGetNodeText} from './utils';
+import stripBom from 'lib/stripBom';
+
+function parseGpx(txt, name, preferNameFromFile) {
+ var error;
+
+ function getSegmentPoints(segment_element) {
+ var points_elements = segment_element.getElementsByTagName('trkpt');
+ var points = [];
+ for (var i = 0; i < points_elements.length; i++) {
+ var point_element = points_elements[i];
+ var lat = parseFloat(point_element.getAttribute('lat'));
+ var lng = parseFloat(point_element.getAttribute('lon'));
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ points.push({lat: lat, lng: lng});
+ }
+ return points;
+ }
+
+ var getTrackSegments = function(xml) {
+ var segments = [];
+ var segments_elements = xml.getElementsByTagName('trkseg');
+ for (var i = 0; i < segments_elements.length; i++) {
+ var segment_points = getSegmentPoints(segments_elements[i]);
+ if (segment_points.length) {
+ segments.push(segment_points);
+ }
+ }
+ return segments;
+ };
+
+ function getRoutePoints(rte_element) {
+ var points_elements = rte_element.getElementsByTagName('rtept');
+ var points = [];
+ for (var i = 0; i < points_elements.length; i++) {
+ var point_element = points_elements[i];
+ var lat = parseFloat(point_element.getAttribute('lat'));
+ var lng = parseFloat(point_element.getAttribute('lon'));
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ points.push({lat: lat, lng: lng});
+ }
+ return points;
+ }
+
+ var getRoutes = function(xml) {
+ var routes = [];
+ var rte_elements = xml.getElementsByTagName('rte');
+ for (var i = 0; i < rte_elements.length; i++) {
+ var rte_points = getRoutePoints(rte_elements[i]);
+ if (rte_points.length) {
+ routes.push(rte_points);
+ }
+ }
+ return routes;
+ };
+
+ var getWaypoints = function(xml) {
+ var waypoint_elements = xml.getElementsByTagName('wpt');
+ var waypoints = [];
+ for (var i = 0; i < waypoint_elements.length; i++) {
+ var waypoint_element = waypoint_elements[i];
+ var waypoint = {};
+ waypoint.lat = parseFloat(waypoint_element.getAttribute('lat'));
+ waypoint.lng = parseFloat(waypoint_element.getAttribute('lon'));
+ if (isNaN(waypoint.lat) || isNaN(waypoint.lng)) {
+ error = 'CORRUPT';
+ continue;
+ }
+ let wptName = xmlGetNodeText(waypoint_element.getElementsByTagName('name')[0]) || '';
+ try {
+ wptName = utf8_decode((wptName));
+ } catch (e) {
+ error = 'CORRUPT';
+ wptName = '__invalid point name__';
+ }
+ waypoint.name = wptName;
+ waypoint.symbol_name = xmlGetNodeText(waypoint_element.getElementsByTagName('sym')[0]);
+ waypoints.push(waypoint);
+ }
+ return waypoints;
+ };
+
+ txt = stripBom(txt);
+ // remove namespaces
+ txt = txt.replace(/<([^ >]+):([^ >]+)/g, '<$1_$2');
+ try {
+ var dom = (new DOMParser()).parseFromString(txt, "text/xml");
+ } catch (e) {
+ return null;
+ }
+ if (dom.documentElement.nodeName === 'parsererror') {
+ return null;
+ }
+ if (dom.getElementsByTagName('gpx').length === 0) {
+ return null;
+ }
+ if (preferNameFromFile) {
+ for (let trk of [...dom.getElementsByTagName('trk')]) {
+ let trkName = trk.getElementsByTagName('name')[0];
+ if (trkName) {
+ try {
+ trkName = utf8_decode(xmlGetNodeText(trkName));
+ } catch (e) {
+ error = 'CORRUPT';
+ }
+ if (trkName.length) {
+ name = trkName;
+ break;
+ }
+ }
+ }
+ }
+ return [{
+ name: name,
+ tracks: getTrackSegments(dom).concat(getRoutes(dom)),
+ points: getWaypoints(dom),
+ error: error
+ }];
+}
+
+export default parseGpx;
+\ No newline at end of file
diff --git a/src/lib/leaflet.control.track-list/lib/jsInflate.js b/src/lib/leaflet.control.track-list/lib/jsInflate.js
@@ -0,0 +1,13 @@
+import tynyInflate from 'tiny-inflate';
+import {stringToArrayBuffer, arrayBufferToString} from 'lib/binary-strings';
+
+function jsInflate(compressed, originalSize) {
+ if (originalSize === 0) {
+ return '';
+ }
+ const out = new Uint8Array(originalSize);
+ tynyInflate(new Uint8Array(stringToArrayBuffer(compressed)), out);
+ return arrayBufferToString(out);
+}
+
+export default jsInflate;
diff --git a/src/lib/leaflet.control.track-list/lib/kml.js b/src/lib/leaflet.control.track-list/lib/kml.js
@@ -0,0 +1,162 @@
+import {decode as utf8_decode} from 'utf8';
+import {xmlGetNodeText} from './utils';
+import stripBom from 'lib/stripBom';
+import JSUnzip from 'vendored/github.com/augustl/js-unzip/js-unzip';
+import jsInflate from './jsInflate';
+
+function parseKml(txt, name) {
+ var error;
+ var getSegmentPoints = function(coordinates_element) {
+ // convert multiline text value of tag to single line
+ var coordinates_string = xmlGetNodeText(coordinates_element);
+ var points_strings = coordinates_string.split(/\s+/);
+ var points = [];
+ for (var i = 0; i < points_strings.length; i++) {
+ if (points_strings[i].length) {
+ var point = points_strings[i].split(',');
+ var lat = parseFloat(point[1]);
+ var lng = parseFloat(point[0]);
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ points.push({lat: lat, lng: lng});
+ }
+ }
+ return points;
+ };
+
+ var getTrackSegments = function(xml) {
+ var segments_elements = xml.getElementsByTagName('LineString');
+ var segments = [];
+ for (var i = 0; i < segments_elements.length; i++) {
+ var coordinates_element = segments_elements[i].getElementsByTagName('coordinates');
+ if (coordinates_element.length) {
+ var segment_points = getSegmentPoints(coordinates_element[0]);
+ if (segment_points.length) {
+ segments.push(segment_points);
+ }
+ }
+ }
+ return segments;
+ };
+
+ function getPoints(dom) {
+ var points = [],
+ placemarks, i, coord, name, lat, lng, pointObjs;
+ placemarks = dom.getElementsByTagName('Placemark');
+ for (i = 0; i < placemarks.length; i++) {
+ pointObjs = placemarks[i].getElementsByTagName('Point');
+ if (pointObjs.length === 0) {
+ continue
+ } else if (pointObjs.length > 1) {
+ error = 'CORRUPT';
+ break;
+ }
+ coord = pointObjs[0].getElementsByTagName('coordinates');
+ if (coord.length !== 1) {
+ error = 'CORRUPT';
+ break;
+ }
+ coord = xmlGetNodeText(coord[0]);
+ coord = coord.split(',');
+ lat = parseFloat(coord[1]);
+ lng = parseFloat(coord[0]);
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ name = placemarks[i].getElementsByTagName('name');
+ if (name.length !== 1) {
+ error = 'CORRUPT';
+ break;
+ }
+ try {
+ name = utf8_decode(xmlGetNodeText(name[0])).trim();
+ } catch (e) {
+ error = 'CORRUPT';
+ break;
+ }
+ points.push({
+ name: name,
+ lat: lat,
+ lng: lng
+ }
+ );
+ }
+ return points;
+ }
+
+ txt = stripBom(txt);
+ txt = txt.replace(/<([^ >]+):([^ >]+)/g, '<$1_$2');
+ try {
+ var dom = (new DOMParser()).parseFromString(txt, "text/xml");
+ } catch (e) {
+ return null;
+ }
+ if (dom.documentElement.nodeName === 'parsererror') {
+ return null;
+ }
+ if (dom.getElementsByTagName('kml').length === 0) {
+ return null;
+ }
+
+ return [{name: name, tracks: getTrackSegments(dom), points: getPoints(dom), error: error}];
+}
+
+function parseKmz(txt, name) {
+ var uncompressed;
+ try {
+ var unzipper = new JSUnzip(txt);
+ } catch (e) {
+ return null;
+ }
+ var tracks = [],
+ points = [],
+ geodata,
+ error;
+ var hasDocKml = false;
+ if (!unzipper.isZipFile()) {
+ return null;
+ }
+ try {
+ unzipper.readEntries();
+ } catch (e) {
+ return null;
+ }
+ var i, entry;
+ for (i = 0; i < unzipper.entries.length; i++) {
+ entry = unzipper.entries[i];
+ if (entry.fileName === 'doc.kml') {
+ hasDocKml = true;
+ break;
+ }
+ }
+ if (!hasDocKml) {
+ return null;
+ }
+
+ for (i = 0; i < unzipper.entries.length; i++) {
+ entry = unzipper.entries[i];
+ if (entry.fileName.match(/\.kml$/i)) {
+ if (entry.compressionMethod === 0) {
+ uncompressed = entry.data;
+ } else if (entry.compressionMethod === 8) {
+ uncompressed = jsInflate(entry.data, entry.uncompressedSize);
+ } else {
+ return null;
+ }
+ geodata = parseKml(uncompressed, 'dummmy');
+ if (geodata) {
+ error = error || geodata[0].error;
+ tracks.push.apply(tracks, geodata[0].tracks);
+ points.push.apply(points, geodata[0].points);
+ }
+ }
+ }
+
+ geodata = [{name: name, error: error, tracks: tracks, points: points}];
+ return geodata;
+}
+
+export {parseKml, parseKmz}
+\ No newline at end of file
diff --git a/src/lib/leaflet.control.track-list/lib/nktk.js b/src/lib/leaflet.control.track-list/lib/nktk.js
@@ -390,5 +390,13 @@ function nakarteLinkParser(_, responses) {
return parseNktkSequence(responses[0].responseBinaryText);
}
+function parseTrackUrl(s) {
+ var i = s.indexOf('track://');
+ if (i === -1) {
+ return null;
+ }
+ return parseTrackUrlData(s.substring(i + 8));
+}
+
export {saveNktk, parseTrackUrlData, parseNakarteUrl, isNakarteLinkUrl, nakarteLinkRequestOptions,
- nakarteLinkParser, parseNktkSequence};
-\ No newline at end of file
+ nakarteLinkParser, parseNktkSequence, parseTrackUrl};
+\ No newline at end of file
diff --git a/src/lib/leaflet.control.track-list/lib/ozi.js b/src/lib/leaflet.control.track-list/lib/ozi.js
@@ -0,0 +1,116 @@
+import {decodeCP1251} from './utils';
+import stripBom from 'lib/stripBom';
+
+function parseOziRte(txt, name) {
+ let error, segments = [];
+ txt = stripBom(txt);
+ const lines = txt.split('\n');
+ if (lines[0].indexOf('OziExplorer Route File') !== 0) {
+ return null;
+ }
+ let currentSegment = [];
+ for (let i=4; i < lines.length; i++) {
+ let line = lines[i].trim();
+ if (!line) {
+ continue;
+ }
+ let fields = line.split(',');
+ if (fields[0] === 'R') {
+ if (currentSegment.length) {
+ segments.push(currentSegment);
+ }
+ currentSegment = [];
+ } else if (fields[0] === 'W') {
+ let lat = parseFloat(fields[5]);
+ let lng = parseFloat(fields[6]);
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ currentSegment.push({lat, lng});
+ } else {
+ error = 'CORRUPT';
+ break
+ }
+ }
+ if (currentSegment.length) {
+ segments.push(currentSegment);
+ }
+ return [{name, tracks: segments, error}];
+}
+
+function parseOziPlt(txt, name) {
+ var error;
+ var segments = [];
+ txt = stripBom(txt);
+ var lines = txt.split('\n');
+ if (lines[0].indexOf('OziExplorer Track Point File') !== 0) {
+ return null;
+ }
+ var expected_points_num = parseInt(lines[5], 10);
+ var current_segment = [];
+ var total_points_num = 0;
+ for (var i = 6; i < lines.length; i++) {
+ var line = lines[i].trim();
+ if (!line) {
+ continue;
+ }
+ var fields = line.split(',');
+ var lat = parseFloat(fields[0]);
+ var lon = parseFloat(fields[1]);
+ var is_start_of_segment = parseInt(fields[2], 10);
+ if (isNaN(lat) || isNaN(lon) || isNaN(is_start_of_segment)) {
+ error = 'CORRUPT';
+ break;
+ }
+ if (is_start_of_segment) {
+ current_segment = [];
+ }
+ if (!current_segment.length) {
+ segments.push(current_segment);
+ }
+ current_segment.push({lat: lat, lng: lon});
+ total_points_num += 1;
+ }
+ if (isNaN(expected_points_num) || (expected_points_num !== 0 && expected_points_num !== total_points_num)) {
+ error = 'CORRUPT';
+ }
+ return [{name: name, tracks: segments, error: error}];
+}
+
+
+function parseOziWpt(txt, name) {
+ var points = [],
+ error,
+ lines, line,
+ i,
+ lat, lng, pointName, fields;
+ txt = stripBom(txt);
+ lines = txt.split('\n');
+ if (lines[0].indexOf('OziExplorer Waypoint File') !== 0) {
+ return null;
+ }
+ for (i = 4; i < lines.length; i++) {
+ line = lines[i].trim();
+ if (!line) {
+ continue;
+ }
+ fields = line.split(',');
+ lat = parseFloat(fields[2]);
+ lng = parseFloat(fields[3]);
+ pointName = decodeCP1251(fields[1]).trim();
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ points.push({
+ lat: lat,
+ lng: lng,
+ name: pointName
+ }
+ );
+ }
+ return [{name: name, points: points, error: error}];
+}
+
+export {parseOziPlt, parseOziRte, parseOziWpt};
+\ No newline at end of file
diff --git a/src/lib/leaflet.control.track-list/lib/utils.js b/src/lib/leaflet.control.track-list/lib/utils.js
@@ -0,0 +1,47 @@
+function xmlGetNodeText(node) {
+ if (node) {
+ return Array.prototype.slice.call(node.childNodes)
+ .map(function(node) {
+ return node.nodeValue;
+ }
+ )
+ .join('');
+ }
+}
+
+function decode866(s) {
+ var c, i, s2 = [];
+ for (i = 0; i < s.length; i++) {
+ c = s.charCodeAt(i);
+ if (c >= 128 && c <= 175) {
+ c += (0x410 - 128);
+ } else if (c >= 224 && c <= 239) {
+ c += (0x440 - 224);
+ } else if (c === 240) {
+ c = 0x0401;
+ } else if (c === 241) {
+ c = 0x0451;
+ }
+ s2.push(String.fromCharCode(c));
+ }
+ return s2.join('');
+}
+
+function decodeCP1251(s) {
+ var c, i, s2 = [];
+ for (i = 0; i < s.length; i++) {
+ c = s.charCodeAt(i);
+ if (c >= 192 && c <= 255) {
+ c += (0x410 - 192);
+ } else if (c === 168) {
+ c = 0x0401;
+ } else if (c === 184) {
+ c = 0x0451;
+ }
+ s2.push(String.fromCharCode(c));
+ }
+ return s2.join('');
+}
+
+export {xmlGetNodeText, decode866, decodeCP1251};
+
diff --git a/src/lib/leaflet.control.track-list/lib/yandex.js b/src/lib/leaflet.control.track-list/lib/yandex.js
@@ -0,0 +1,92 @@
+function parseYandexRulerString(s) {
+ var last_lat = 0;
+ var last_lng = 0;
+ var error;
+ var points = [];
+ s = s.replace(/%2C/ig, ',');
+ var points_str = s.split('~');
+ for (var i = 0; i < points_str.length; i++) {
+ var point = points_str[i].split(',');
+ var lng = parseFloat(point[0]);
+ var lat = parseFloat(point[1]);
+ if (isNaN(lat) || isNaN(lng)) {
+ error = 'CORRUPT';
+ break;
+ }
+ last_lng += lng;
+ last_lat += lat;
+ points.push({lat: last_lat, lng: last_lng});
+ }
+ return {error: error, points: points};
+}
+
+
+function parseYandexRulerUrl(s) {
+ var re = /yandex\..+[?&]rl=([^&]+)/;
+ var m = re.exec(s);
+ if (!m) {
+ return null;
+ }
+ var res = parseYandexRulerString(m[1]);
+ return [{name: 'Yandex ruler', error: res.error, tracks: [res.points]}];
+}
+
+// function parseYandexMap(txt) {
+// var start_tag = '<script id="vpage" type="application/json">';
+// var json_start = txt.indexOf(start_tag);
+// if (json_start === -1) {
+// return null;
+// }
+// json_start += start_tag.length;
+// var json_end = txt.indexOf('</script>', json_start);
+// if (json_end === -1) {
+// return null;
+// }
+// var map_data = txt.substring(json_start, json_end);
+// map_data = JSON.parse(map_data);
+// console.log(map_data);
+// if (!('request' in map_data)) {
+// return null;
+// }
+// var name = 'YandexMap';
+// var segments = [];
+// var error;
+// if (map_data.vpage && map_data.vpage.data && map_data.vpage.data.objects && map_data.vpage.data.objects.length) {
+// var mapName = ('' + (map_data.vpage.data.name || '')).trim();
+// if (mapName.length > 3) {
+// name = '';
+// } else if (mapName.length) {
+// name += ': ';
+// }
+// name += fileutils.decodeUTF8(mapName);
+// map_data.vpage.data.objects.forEach(function(obj){
+// if (obj.pts && obj.pts.length) {
+// var segment = [];
+// for (var i=0; i< obj.pts.length; i++) {
+// var pt = obj.pts[i];
+// var lng = parseFloat(pt[0]);
+// var lat = parseFloat(pt[1]);
+// if (isNaN(lat) || isNaN(lng)) {
+// error = 'CORRUPT';
+// break;
+// }
+// segment.push({lat: lat, lng:lng});
+// }
+// if (segment.length) {
+// segments.push(segment);
+// }
+// }
+// });
+// }
+// if (map_data.request.args && map_data.request.args.rl) {
+// var res = parseYandexRulerString(map_data.request.args.rl);
+// error = error || res.error;
+// if (res.points && res.points.length) {
+// segments.push(res.points);
+// }
+// }
+// return [{name: name, error: error, tracks: segments}];
+// }
+
+
+export {parseYandexRulerUrl}
+\ No newline at end of file
diff --git a/src/lib/leaflet.control.track-list/lib/zip.js b/src/lib/leaflet.control.track-list/lib/zip.js
@@ -0,0 +1,43 @@
+import JSUnzip from 'vendored/github.com/augustl/js-unzip/js-unzip';
+import jsInflate from './jsInflate';
+import {decode866} from './utils';
+import {parseGeoFile} from './geo_file_formats';
+
+function parseZip(txt, name) {
+ try {
+ var unzipper = new JSUnzip(txt);
+ } catch (e) {
+ return null;
+ }
+ if (!unzipper.isZipFile()) {
+ return null;
+ }
+ try {
+ unzipper.readEntries();
+ } catch (e) {
+ return null;
+ }
+ var geodata_array = [];
+ for (var i = 0; i < unzipper.entries.length; i++) {
+ var entry = unzipper.entries[i];
+ var uncompressed;
+ if (entry.compressionMethod === 0) {
+ uncompressed = entry.data;
+ } else if (entry.compressionMethod === 8) {
+ uncompressed = jsInflate(entry.data, entry.uncompressedSize);
+ } else {
+ return null;
+ }
+ var file_name = decode866(entry.fileName);
+ var geodata = parseGeoFile(file_name, uncompressed);
+ for (let item of geodata) {
+ if (item.error === 'UNSUPPORTED' && item.name.match(/\.pdf$|\.doc$|\.txt$\.jpg$/)) {
+ continue;
+ }
+ geodata_array.push(item)
+ }
+ }
+ return geodata_array;
+}
+
+export default parseZip;
+\ No newline at end of file