1 package tim.prune.function.srtm;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.io.InputStream;
7 import java.io.IOException;
9 import java.net.HttpURLConnection;
10 import java.util.zip.ZipEntry;
11 import java.util.zip.ZipInputStream;
13 import tim.prune.GpsPrune;
16 * Abstract class implemented by each download source
18 public abstract class SrtmSource {
21 * A string used to build function.downloadsrtm.getName() for getting
22 * the string shown to the user in menus and messages, also used to
23 * build cache directory
25 public abstract String getName();
28 * Whether the source is ready to use
29 * @return true, or false if configuration is necessary
31 public abstract boolean isReadyToUse();
34 * Download one tile of SRTM data to cache
35 * @param inTile the tile to get
37 public abstract boolean downloadTile(SrtmTile inTile)
38 throws SrtmSourceException;
41 * Returns the number of rows of the tile
43 * Tiles from viewfinderpanoramas have different resolutions depending
45 * @param inTile the tile whose size we want
46 * @return number of rows; 1201 or 3601 in current implementation
48 public abstract int getRowSize(SrtmTile inTile);
51 * Whether the tile is cached
52 * @return true if the tile is in the cache and ready to be used
54 public boolean isCached(SrtmTile inTile)
56 File cachedFileName = getCacheFileName(inTile);
57 return cachedFileName != null &&
58 getCacheFileName(inTile).exists();
62 * Get the heigths for that tile
64 * @return an one-dimentional array of size {@link getRowSize ** 2}
65 * @throws SrtmSourceException notably if the tile is not cached yet
67 public int[] getTileHeights(SrtmTile inTile)
68 throws SrtmSourceException
70 File cacheFileName = getCacheFileName(inTile);
71 if (cacheFileName == null)
73 throw new SrtmSourceException("Tile "+inTile.getTileName()+" not in cache");
77 ZipInputStream inStream = new ZipInputStream(new FileInputStream(cacheFileName));
78 ZipEntry entry = inStream.getNextEntry();
79 int rowSize = getRowSize(inTile);
80 int tileSize = rowSize * rowSize;
81 if (entry.getSize() != 2 * tileSize)
83 throw new SrtmSourceException("Tile file "+cacheFileName+" does not have the expected size");
85 return slurpTileHeigths(inStream, tileSize);
89 throw new SrtmSourceException("Failure opening "+cacheFileName+" for reading:"+e.getMessage());
94 // helpers used internally by the client classes
95 protected abstract String getSourceExtension();
98 * Returns the cache directory for tiles, a sub-directory of the map
101 protected File getCacheDir()
103 return SrtmDiskCache.getCacheDir(getName());
107 * Return the name of the filename for that tile
108 * For viewfinderpanoramas.org tiles, that might be a ZIP file
109 * containing several tiles
111 protected File getCacheFileName(SrtmTile inTile)
113 String fileName = inTile.getTileName() + getSourceExtension();
114 return new File(getCacheDir(), fileName);
117 protected InputStream getStreamToUrl(URL inTileUrl)
118 throws SrtmSourceException
122 HttpURLConnection conn = (HttpURLConnection) inTileUrl.openConnection();
123 conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
124 int status = conn.getResponseCode();
127 return conn.getInputStream();
129 else if (status == 404)
131 throw new SrtmSourceException("Tile not found: "+conn.getURL());
135 throw new SrtmSourceException("Invalid response from server: " +status+conn.getContent());
138 catch (IOException e)
140 throw new SrtmSourceException("Error while downloading tile from "+inTileUrl+": "+e.getMessage());
145 * Helper for downloadTile()
146 * @param inStream Stream to read from, typically from HTTP connection
147 * @param outputFile Where to save the data being read
149 protected boolean readToFile(InputStream inStream, File outputFile)
150 throws SrtmSourceException
154 FileOutputStream outStream = new FileOutputStream(outputFile);
156 byte[] buffer = new byte[4096];
158 while ((read = inStream.read(buffer)) != -1)
160 outStream.write(buffer, 0, read);
162 // Make sure streams are closed
163 try {inStream.close();} catch (Exception e) {}
164 try {outStream.close();} catch (Exception e) {}
167 catch (IOException e)
169 throw new SrtmSourceException("Error downloading tile:" + e.getMessage());
174 * Helper for getTileHeights
175 * @param inStream Stream to read from, assumed to have been advanced
176 * to the appropriate tile
177 * @param tileSize the expected tileSize (square of getRowSize; assumed
178 * to have been checked by the caller)
179 * @return the tile heights
181 protected int[] slurpTileHeigths(ZipInputStream inStream, int tileSize)
184 int[] heights = new int[tileSize];
185 int dataSize = 2 * tileSize;
186 byte[] buffer = new byte[dataSize];
187 // Read entire file contents into one byte array
189 while (alreadyRead < dataSize)
191 alreadyRead += inStream.read(buffer, alreadyRead, dataSize - alreadyRead);
193 for (int i = 0; i < tileSize; i++)
195 // Bytes are signed. Cast high-order to int with sign
196 // extension, and clamp low-order to its unsigned range
197 heights[i] = buffer[2 * i] * 256 + (0xff & buffer[2 * i + 1]);