aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/files
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/files')
-rw-r--r--main/src/cgeo/geocaching/files/FileParser.java8
-rw-r--r--main/src/cgeo/geocaching/files/FileType.java8
-rw-r--r--main/src/cgeo/geocaching/files/FileTypeDetector.java77
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java103
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java4
-rw-r--r--main/src/cgeo/geocaching/files/LocParser.java11
6 files changed, 169 insertions, 42 deletions
diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java
index 396a589..973e65f 100644
--- a/main/src/cgeo/geocaching/files/FileParser.java
+++ b/main/src/cgeo/geocaching/files/FileParser.java
@@ -4,6 +4,8 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.CancellableHandler;
import org.apache.commons.io.IOUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
@@ -29,7 +31,7 @@ public abstract class FileParser {
* @throws ParserException
* if the input stream contains data not matching the file format of the parser
*/
- public abstract Collection<Geocache> parse(final InputStream stream, final CancellableHandler progressHandler) throws IOException, ParserException;
+ public abstract Collection<Geocache> parse(@NonNull final InputStream stream, @Nullable final CancellableHandler progressHandler) throws IOException, ParserException;
/**
* Convenience method for parsing a file.
@@ -49,7 +51,7 @@ public abstract class FileParser {
}
}
- protected static StringBuilder readStream(InputStream is, CancellableHandler progressHandler) throws IOException {
+ protected static StringBuilder readStream(@NonNull final InputStream is, @Nullable final CancellableHandler progressHandler) throws IOException {
final StringBuilder buffer = new StringBuilder();
ProgressInputStream progressInputStream = new ProgressInputStream(is);
final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream, "UTF-8"));
@@ -66,7 +68,7 @@ public abstract class FileParser {
}
}
- protected static void showProgressMessage(final CancellableHandler handler, final int bytesRead) {
+ protected static void showProgressMessage(@Nullable final CancellableHandler handler, final int bytesRead) {
if (handler != null) {
if (handler.isCancelled()) {
throw new CancellationException();
diff --git a/main/src/cgeo/geocaching/files/FileType.java b/main/src/cgeo/geocaching/files/FileType.java
new file mode 100644
index 0000000..ef62351
--- /dev/null
+++ b/main/src/cgeo/geocaching/files/FileType.java
@@ -0,0 +1,8 @@
+package cgeo.geocaching.files;
+
+public enum FileType {
+ UNKNOWN,
+ LOC,
+ GPX,
+ ZIP
+}
diff --git a/main/src/cgeo/geocaching/files/FileTypeDetector.java b/main/src/cgeo/geocaching/files/FileTypeDetector.java
new file mode 100644
index 0000000..389b83a
--- /dev/null
+++ b/main/src/cgeo/geocaching/files/FileTypeDetector.java
@@ -0,0 +1,77 @@
+package cgeo.geocaching.files;
+
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class FileTypeDetector {
+
+ private final ContentResolver contentResolver;
+ private final Uri uri;
+
+ public FileTypeDetector(Uri uri, ContentResolver contentResolver) {
+ this.uri = uri;
+ this.contentResolver = contentResolver;
+ }
+
+ public @NonNull FileType getFileType() {
+ InputStream is = null;
+ BufferedReader reader = null;
+ FileType type = FileType.UNKNOWN;
+ try {
+ is = contentResolver.openInputStream(uri);
+ if (is == null) {
+ return FileType.UNKNOWN;
+ }
+ reader = new BufferedReader(new InputStreamReader(is));
+ type = detectHeader(reader);
+ reader.close();
+ } catch (FileNotFoundException e) {
+ Log.e("FileTypeDetector", e);
+ } catch (IOException e) {
+ Log.e("FileTypeDetector", e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ IOUtils.closeQuietly(is);
+ }
+ return type;
+ }
+
+ private static FileType detectHeader(BufferedReader reader)
+ throws IOException {
+ String line = reader.readLine();
+ if (isZip(line)) {
+ return FileType.ZIP;
+ }
+ // scan at most 5 lines of a GPX file
+ for (int i = 0; i < 5; i++) {
+ line = StringUtils.trim(line);
+ if (StringUtils.contains(line, "<loc")) {
+ return FileType.LOC;
+ }
+ if (StringUtils.contains(line, "<gpx")) {
+ return FileType.GPX;
+ }
+ line = reader.readLine();
+ }
+ return FileType.UNKNOWN;
+ }
+
+ private static boolean isZip(String line) {
+ return StringUtils.length(line) >= 4
+ && StringUtils.startsWith(line, "PK") && line.charAt(2) == 3
+ && line.charAt(3) == 4;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java
index cd2f445..52f68e1 100644
--- a/main/src/cgeo/geocaching/files/GPXImporter.java
+++ b/main/src/cgeo/geocaching/files/GPXImporter.java
@@ -12,8 +12,10 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import android.app.Activity;
@@ -93,46 +95,77 @@ public class GPXImporter {
*
* @param uri
* URI of the file to import
- * @param knownMimeType
- * @param knownPathName
+ * @param mimeType
+ * @param pathName
*/
- public void importGPX(final Uri uri, final @Nullable String knownMimeType, final @Nullable String knownPathName) {
+ public void importGPX(final Uri uri, final @Nullable String mimeType, final @Nullable String pathName) {
final ContentResolver contentResolver = fromActivity.getContentResolver();
- String mimeType = knownMimeType;
- final String pathName = knownPathName != null ? knownPathName : uri.getPath();
-
- // if mimetype can't be determined (e.g. for emulators email app), derive it from uri file extension
- // contentResolver.getType(uri) doesn't help but throws exception for emulators email app
- // Permission Denial: reading com.android.email.provider.EmailProvider uri
- // Google search says: there is no solution for this problem
- // Gmail doesn't work at all, see #967
- if (mimeType == null) {
- if (StringUtils.endsWithIgnoreCase(pathName, GPX_FILE_EXTENSION) || StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) {
- mimeType = "application/xml";
- } else {
- // if we can't determine a better type, default to zip import
- // emulator email sends e.g. content://com.android.email.attachmentprovider/1/1/RAW, mimetype=null
- mimeType = "application/zip";
- }
- }
Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
- if (GPX_MIME_TYPES.contains(mimeType)) {
- if (StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) {
- new ImportLocAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else {
- new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- }
- } else if (ZIP_MIME_TYPES.contains(mimeType)) {
- new ImportGpxZipAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
- } else {
- importFinished();
+ @NonNull
+ FileType fileType = new FileTypeDetector(uri, contentResolver)
+ .getFileType();
+
+ if (fileType == FileType.UNKNOWN) {
+ fileType = getFileTypeFromPathName(pathName);
+ }
+ if (fileType == FileType.UNKNOWN) {
+ fileType = getFileTypeFromMimeType(mimeType);
+ }
+
+ ImportThread importer = getImporterFromFileType(uri, contentResolver,
+ fileType);
+
+ if (importer != null) {
+ importer.start();
+ } else {
+ importFinished();
+ }
+ }
+
+ private static @NonNull FileType getFileTypeFromPathName(
+ final String pathName) {
+ if (StringUtils.endsWithIgnoreCase(pathName, GPX_FILE_EXTENSION)) {
+ return FileType.GPX;
}
- }
- /**
- * Import GPX provided via intent of activity that instantiated this GPXImporter.
- */
+ if (StringUtils.endsWithIgnoreCase(pathName, LOC_FILE_EXTENSION)) {
+ return FileType.LOC;
+ }
+ return FileType.UNKNOWN;
+ }
+
+ private static @NonNull FileType getFileTypeFromMimeType(
+ final String mimeType) {
+ if (GPX_MIME_TYPES.contains(mimeType)) {
+ return FileType.GPX;
+ } else if (ZIP_MIME_TYPES.contains(mimeType)) {
+ return FileType.ZIP;
+ }
+ return FileType.UNKNOWN;
+ }
+
+ private ImportThread getImporterFromFileType(Uri uri,
+ ContentResolver contentResolver, FileType fileType) {
+ switch (fileType) {
+ case ZIP:
+ return new ImportGpxZipAttachmentThread(uri, contentResolver,
+ listId, importStepHandler, progressHandler);
+ case GPX:
+ return new ImportGpxAttachmentThread(uri, contentResolver, listId,
+ importStepHandler, progressHandler);
+ case LOC:
+ return new ImportLocAttachmentThread(uri, contentResolver, listId,
+ importStepHandler, progressHandler);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Import GPX provided via intent of activity that instantiated this
+ * GPXImporter.
+ */
public void importGPX() {
final Intent intent = fromActivity.getIntent();
final Uri uri = intent.getData();
@@ -194,7 +227,7 @@ public class GPXImporter {
final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
if (cache != null) {
Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
- StaticMapsProvider.downloadMaps(cache);
+ RxUtils.waitForCompletion(StaticMapsProvider.downloadMaps(cache));
} else {
Log.d("GPXImporter.ImportThread.importStaticMaps: no data found for " + geocode);
}
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index 6161088..f3cd326 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -25,6 +25,8 @@ import cgeo.geocaching.utils.SynchronizedDateFormat;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -270,7 +272,7 @@ public abstract class GPXParser extends FileParser {
}
@Override
- public Collection<Geocache> parse(final InputStream stream, final CancellableHandler progressHandler) throws IOException, ParserException {
+ public Collection<Geocache> parse(@NonNull final InputStream stream, @Nullable final CancellableHandler progressHandler) throws IOException, ParserException {
resetCache();
final RootElement root = new RootElement(namespace, "gpx");
final Element waypoint = root.getChild(namespace, "wpt");
diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java
index 3d01c1b..223fb5a 100644
--- a/main/src/cgeo/geocaching/files/LocParser.java
+++ b/main/src/cgeo/geocaching/files/LocParser.java
@@ -12,6 +12,8 @@ import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
@@ -116,9 +118,9 @@ public final class LocParser extends FileParser {
}
@Override
- public Collection<Geocache> parse(InputStream stream, CancellableHandler progressHandler) throws IOException, ParserException {
- // TODO: progress reporting happens during reading stream only, not during parsing
- String streamContent = readStream(stream, progressHandler).toString();
+ public Collection<Geocache> parse(@NonNull final InputStream stream, @Nullable final CancellableHandler progressHandler) throws IOException, ParserException {
+ final String streamContent = readStream(stream, null).toString();
+ final int maxSize = streamContent.length();
final Map<String, Geocache> coords = parseCoordinates(streamContent);
final List<Geocache> caches = new ArrayList<Geocache>();
for (Entry<String, Geocache> entry : coords.entrySet()) {
@@ -136,6 +138,9 @@ public final class LocParser extends FileParser {
cache.setListId(listId);
cache.setDetailed(true);
cache.store(null);
+ if (progressHandler != null) {
+ progressHandler.sendMessage(progressHandler.obtainMessage(0, maxSize * caches.size() / coords.size(), 0));
+ }
}
Log.i("Caches found in .loc file: " + caches.size());
return caches;