+
+ /**
+ * Get the point source for the specified point
+ * @param inCachers list of GPX cachers to ask for source
+ * @param inPoint point object
+ * @return xml source if available, or null otherwise
+ */
+ private static String getPointSource(GpxCacherList inCachers, DataPoint inPoint)
+ {
+ if (inCachers == null || inPoint == null) {return null;}
+ String source = inCachers.getSourceString(inPoint);
+ if (source == null || !inPoint.isModified()) {return source;}
+ // Point has been modified - maybe it's possible to modify the source
+ source = replaceGpxTags(source, "lat=\"", "\"", inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
+ source = replaceGpxTags(source, "lon=\"", "\"", inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
+ source = replaceGpxTags(source, "<ele>", "</ele>", inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
+ source = replaceGpxTags(source, "<time>", "</time>", inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
+ if (inPoint.isWaypoint()) {source = replaceGpxTags(source, "<name>", "</name>", inPoint.getWaypointName());} // only for waypoints
+ // photo / audio links
+ if (source != null && (inPoint.hasMedia() || source.indexOf("</link>") > 0)) {
+ source = replaceMediaLinks(source, makeMediaLink(inPoint));
+ }
+ return source;
+ }
+
+ /**
+ * Replace the given value into the given XML string
+ * @param inSource source XML for point
+ * @param inStartTag start tag for field
+ * @param inEndTag end tag for field
+ * @param inValue value to replace between start tag and end tag
+ * @return modified String, or null if not possible
+ */
+ private static String replaceGpxTags(String inSource, String inStartTag, String inEndTag, String inValue)
+ {
+ if (inSource == null) {return null;}
+ // Look for start and end tags within source
+ final int startPos = inSource.indexOf(inStartTag);
+ final int endPos = inSource.indexOf(inEndTag, startPos+inStartTag.length());
+ if (startPos > 0 && endPos > 0)
+ {
+ String origValue = inSource.substring(startPos + inStartTag.length(), endPos);
+ if (inValue != null && origValue.equals(inValue)) {
+ // Value unchanged
+ return inSource;
+ }
+ else if (inValue == null || inValue.equals("")) {
+ // Need to delete value
+ return inSource.substring(0, startPos) + inSource.substring(endPos + inEndTag.length());
+ }
+ else {
+ // Need to replace value
+ return inSource.substring(0, startPos+inStartTag.length()) + inValue + inSource.substring(endPos);
+ }
+ }
+ // Value not found for this field in original source
+ if (inValue == null || inValue.equals("")) {return inSource;}
+ return null;
+ }
+
+ /**
+ * Replace the media tags in the given XML string
+ * @param inSource source XML for point
+ * @param inValue value for the current point
+ * @return modified String, or null if not possible
+ */
+ private static String replaceMediaLinks(String inSource, String inValue)
+ {
+ if (inSource == null) {return null;}
+ // Note that this method is very similar to replaceGpxTags except there can be multiple link tags
+ // and the tags must have attributes. So either one heavily parameterized method or two.
+ // Look for start and end tags within source
+ final String STARTTEXT = "<link";
+ final String ENDTEXT = "</link>";
+ final int startPos = inSource.indexOf(STARTTEXT);
+ final int endPos = inSource.lastIndexOf(ENDTEXT);
+ if (startPos > 0 && endPos > 0)
+ {
+ String origValue = inSource.substring(startPos, endPos + ENDTEXT.length());
+ if (inValue != null && origValue.equals(inValue)) {
+ // Value unchanged
+ return inSource;
+ }
+ else if (inValue == null || inValue.equals("")) {
+ // Need to delete value
+ return inSource.substring(0, startPos) + inSource.substring(endPos + ENDTEXT.length());
+ }
+ else {
+ // Need to replace value
+ return inSource.substring(0, startPos) + inValue + inSource.substring(endPos + ENDTEXT.length());
+ }
+ }
+ // Value not found for this field in original source
+ if (inValue == null || inValue.equals("")) {return inSource;}
+ return null;
+ }
+
+ /**
+ * Get the header string for the xml document including encoding
+ * @param inWriter writer object
+ * @return header string defining encoding
+ */
+ private static String getXmlHeaderString(OutputStreamWriter inWriter)
+ {
+ String encoding = inWriter.getEncoding();
+ try {
+ encoding = Charset.forName(encoding).name();
+ }
+ catch (Exception e) {} // ignore failure to find encoding
+ return "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n";
+ }
+
+ /**
+ * Get the header string for the gpx tag
+ * @param inCachers cacher list to ask for headers, if available
+ * @return header string from cachers or as default
+ */
+ private static String getGpxHeaderString(GpxCacherList inCachers)
+ {
+ String gpxHeader = null;
+ if (inCachers != null) {gpxHeader = inCachers.getFirstHeader();}
+ if (gpxHeader == null || gpxHeader.length() < 5)
+ {
+ // Create default (1.0) header
+ gpxHeader = "<gpx version=\"1.0\" creator=\"" + GPX_CREATOR
+ + "\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ + " xmlns=\"http://www.topografix.com/GPX/1/0\""
+ + " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n";
+ }
+ return gpxHeader + "\n";
+ }
+