import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
+import java.net.URL;
+import java.net.HttpURLConnection;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import tim.prune.GpsPrune;
+
+/**
+ * Abstract class implemented by each download source
+ */
public abstract class SrtmSource {
- // methods implemented by each source
+ /**
+ * Name of the source
+ * A string used to build function.downloadsrtm.getName() for getting
+ * the string shown to the user in menus and messages, also used to
+ * build cache directory
+ */
public abstract String getName();
+
+ /**
+ * Whether the source is ready to use
+ * @return true, or false if configuration is necessary
+ */
public abstract boolean isReadyToUse();
+
+ /**
+ * Download one tile of SRTM data to cache
+ * @param inTile the tile to get
+ */
public abstract boolean downloadTile(SrtmTile inTile)
throws SrtmSourceException;
- public abstract int getRowSize(SrtmTile inTile);
- protected abstract String getSourceExtension();
-
- protected boolean downloadToFile(InputStream inStream, File outputFile)
- throws IOException
- {
- FileOutputStream outStream = new FileOutputStream(outputFile);
-
- byte[] buffer = new byte[4096];
- int read = 0;
- while ((read = inStream.read(buffer)) != -1)
- {
- outStream.write(buffer, 0, read);
- }
- // Make sure streams are closed
- try {inStream.close();} catch (Exception e) {}
- try {outStream.close();} catch (Exception e) {}
- return true;
- }
+ /**
+ * Returns the number of rows of the tile
+ *
+ * Tiles from viewfinderpanoramas have different resolutions depending
+ * on the location.
+ * @param inTile the tile whose size we want
+ * @return number of rows; 1201 or 3601 in current implementation
+ */
+ public abstract int getRowSize(SrtmTile inTile);
- protected int[] slurpTileHeigths(ZipInputStream inStream, int tileSize)
- throws IOException
+ /**
+ * Whether the tile is cached
+ * @return true if the tile is in the cache and ready to be used
+ */
+ public boolean isCached(SrtmTile inTile)
{
- int[] heights = new int[tileSize];
- int dataSize = 2 * tileSize;
- byte[] buffer = new byte[dataSize];
- // Read entire file contents into one byte array
- int alreadyRead = 0;
- while (alreadyRead < dataSize)
- {
- alreadyRead += inStream.read(buffer, alreadyRead, dataSize - alreadyRead);
- }
- for (int i = 0; i < tileSize; i++)
- {
- // Bytes are signed. Cast high-order to int with sign
- // extension, and clamp low-order to its unsigned range
- heights[i] = buffer[2 * i] * 256 + (0xff & buffer[2 * i + 1]);
- }
- // Close stream
- inStream.close();
- return heights;
+ File cachedFileName = getCacheFileName(inTile);
+ return cachedFileName != null &&
+ getCacheFileName(inTile).exists();
}
+ /**
+ * Get the heigths for that tile
+ *
+ * @return an one-dimentional array of size {@link getRowSize ** 2}
+ * @throws SrtmSourceException notably if the tile is not cached yet
+ */
public int[] getTileHeights(SrtmTile inTile)
throws SrtmSourceException
{
}
+ // helpers used internally by the client classes
+ protected abstract String getSourceExtension();
+
+ /**
+ * Returns the cache directory for tiles, a sub-directory of the map
+ * cache
+ */
protected File getCacheDir()
{
return SrtmDiskCache.getCacheDir(getName());
}
+ /**
+ * Return the name of the filename for that tile
+ * For viewfinderpanoramas.org tiles, that might be a ZIP file
+ * containing several tiles
+ */
protected File getCacheFileName(SrtmTile inTile)
{
String fileName = inTile.getTileName() + getSourceExtension();
return new File(getCacheDir(), fileName);
}
- public boolean isCached(SrtmTile inTile)
+ protected InputStream getStreamToUrl(URL inTileUrl)
+ throws SrtmSourceException
{
- File cachedFileName = getCacheFileName(inTile);
- return cachedFileName != null &&
- getCacheFileName(inTile).exists();
+ try
+ {
+ HttpURLConnection conn = (HttpURLConnection) inTileUrl.openConnection();
+ conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
+ int status = conn.getResponseCode();
+ if (status == 200)
+ {
+ return conn.getInputStream();
+ }
+ else if (status == 404)
+ {
+ throw new SrtmSourceException("Tile not found: "+conn.getURL());
+ }
+ else
+ {
+ throw new SrtmSourceException("Invalid response from server: " +status+conn.getContent());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new SrtmSourceException("Error while downloading tile from "+inTileUrl+": "+e.getMessage());
+ }
+ }
+
+ /**
+ * Helper for downloadTile()
+ * @param inStream Stream to read from, typically from HTTP connection
+ * @param outputFile Where to save the data being read
+ */
+ protected boolean readToFile(InputStream inStream, File outputFile)
+ throws SrtmSourceException
+ {
+ try
+ {
+ FileOutputStream outStream = new FileOutputStream(outputFile);
+
+ byte[] buffer = new byte[4096];
+ int read = 0;
+ while ((read = inStream.read(buffer)) != -1)
+ {
+ outStream.write(buffer, 0, read);
+ }
+ // Make sure streams are closed
+ try {inStream.close();} catch (Exception e) {}
+ try {outStream.close();} catch (Exception e) {}
+ return true;
+ }
+ catch (IOException e)
+ {
+ throw new SrtmSourceException("Error downloading tile:" + e.getMessage());
+ }
+ }
+
+ /**
+ * Helper for getTileHeights
+ * @param inStream Stream to read from, assumed to have been advanced
+ * to the appropriate tile
+ * @param tileSize the expected tileSize (square of getRowSize; assumed
+ * to have been checked by the caller)
+ * @return the tile heights
+ */
+ protected int[] slurpTileHeigths(ZipInputStream inStream, int tileSize)
+ throws IOException
+ {
+ int[] heights = new int[tileSize];
+ int dataSize = 2 * tileSize;
+ byte[] buffer = new byte[dataSize];
+ // Read entire file contents into one byte array
+ int alreadyRead = 0;
+ while (alreadyRead < dataSize)
+ {
+ alreadyRead += inStream.read(buffer, alreadyRead, dataSize - alreadyRead);
+ }
+ for (int i = 0; i < tileSize; i++)
+ {
+ // Bytes are signed. Cast high-order to int with sign
+ // extension, and clamp low-order to its unsigned range
+ heights[i] = buffer[2 * i] * 256 + (0xff & buffer[2 * i + 1]);
+ }
+ // Close stream
+ inStream.close();
+ return heights;
}
}