📄 waddata.java
字号:
package org.placelab.demo.mapview;//import java.io.FileOutputStream;import java.io.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.Enumeration;import java.util.Hashtable;import java.util.NoSuchElementException;import java.util.zip.ZipEntry;import java.util.zip.ZipFile;import org.eclipse.swt.graphics.ImageData;import org.placelab.core.PlacelabProperties;import org.placelab.mapper.JDBMMapper;import org.placelab.mapper.MapLoader;import org.placelab.util.StringUtil;import org.placelab.util.ZipUtil;/** * This class reads a map wad and gets out all the maps and allows * accessing of all the maps and places in it. Alternatively, it can * write a map wad. * * <pre> * Hashtable Wads are zip files with the following structure: * + map.wad * - apcache.txt (a text file of the aps like from placelab.org) * - defaults.txt (a SectionedFile described below) * + maps * - maps.index (a SectionedFile described below) * - mapname.jpg/gif/png OR mapname.tiger.zip (us census tiger format data) * - mapname.meta (a SectionedFile described below) * + places * - places.index (a SectionedFile described below) * - place-set-name.txt (a SectionedFile described below) * - icons * - beer-icon.jpg/gif/png * * maps.index has the following structure * [Maps] * mapname=mapname.meta * * * mapname.meta has the following structure * [Map] * # origin_lat and origin_lon are lower left corner values * origin_lat=47.349829 * origin_lon=-122.98327 * pixels_per_lat=100.01 * pixels_per_lon=9994.39828 * # OR you may specify the upper right corner's lat and lon * upper_right_lat=47.449829 * upper_right_lon=-122.99327 * * image=images/mapimage1.jpg/gif/png * * NEW: alternatively you can specify the following structure * for us census tiger data embedded in a mapwad: * [TigerMap] * data=maps/mapname.tiger.txt * * The Tiger data is the type 1 and type 2 record files * concatenated together in that order. This is likely * to change in the future. * * * places.index has the following structure * [Places] * place-set-name=place-set-name.txt * * * place-set-name.txt has the following structure * [place name] * # image references are relative to the root of the wad * icon_file=places/icons/beer_icon.jpg * lat=46.19829 * lon=-122.8132 * text=Some descriptive text * url=http://www.whitehouse.gov * type=radical/AP/etc * * [other place name] * etc ... * * defaults.txt has the following structure * [Map] * mapname=1 * * [Places] * placeset1=1 * placeset2=1 * placeset3=1 * # ... and as many place sets as you would like to specify * </pre> * * the defaults file specifies what the wad author thinks should * be the first set of things that people might want to see. There * is no guarantee that they will be the first things displayed, it * is only a suggestion. Also note that while you must specify * a map if you have a defaults file, you needn't specify any place * sets. Defaults files are not required. * * Note that while place set definition file references in places.index * are relative references, the image file references actually in the place * set files are relative to the root of the wad. This is done so that people * can put their images wherever they want in the wad, since ../ type * references are not allowed. * */public class WadData { // this is a Hashtable of maps protected Hashtable maps; // this is a Hashtable of Hashtables of places // where <place set name> => <place set> and a <place set> is // a hashtable where <place name> => <PlaceBacking object> protected Hashtable places; // I only want to have at most 1 copy of each image in memory at // once protected Hashtable imageResources; protected String defaultMap; protected Hashtable defaultPlaces; private static final String mapsDirKey = "maps/"; private static final String placesDirKey = "places/"; private static final String mapsIndexKey = "maps/maps.index"; private static final String placesIndexKey = "places/places.index"; private static final String apCacheKey = "apcache.txt"; private static final String defaultsKey = "defaults.txt"; private String myApCacheKey = apCacheKey; protected ZipFile wad; /* Load all the map data out of a given wad and into memory */ public WadData(String pathToWad) throws IOException, WadDataFormatException { this(); wad = new ZipFile(normalizePath(pathToWad)); String s = (String)PlacelabProperties.get("placelab.apcache"); if ((s != null) && (s.length() > 0)) { myApCacheKey = s; } this.loadMaps(); this.loadPlaces(); this.loadDefaults(); } // this does some business so that // a) wads in the placelab.mapwaddir are found // b) directories structured in the form of a wad // can be read private String normalizePath(String path) throws IOException { File file = new File(path); if(file.exists()) { if(file.isDirectory()) { return fromDir(path); } else { return file.getAbsolutePath(); } } else { // try to construct a file relative to the mapwad dir if(file.isAbsolute()) { throw new FileNotFoundException(path); } else { String path2 = PlacelabProperties.get("placelab.mapwaddir") + File.separator + path; file = new File(path2); if(file.exists()) { if(file.isDirectory()) { return fromDir(path2); } else { return file.getAbsolutePath(); } } else { throw new FileNotFoundException("neither " + path2 + " nor " + path + "exists"); } } } } private String fromDir(String path) throws IOException { File file = new File(path); File tmp = File.createTempFile(file.getName(), ".zip"); ZipUtil.dirToZip(new File(path), tmp); return tmp.getAbsolutePath(); } /* create a new wad to be loaded for writing */ public WadData() { maps = new Hashtable(); places = new Hashtable(); imageResources = new Hashtable(); } /* methods related to reading map wads */ private void loadDefaults() throws IOException, WadDataFormatException { ZipEntry defaultsEntry = wad.getEntry(defaultsKey); if(defaultsEntry == null || defaultsEntry.isDirectory()) { // its ok not to have any defaults defaultMap = null; defaultPlaces = null; return; } InputStream defStream = wad.getInputStream(defaultsEntry); SectionedFileParser defParser = null; try { defParser = new SectionedFileParser(defStream); } catch (SectionedFileFormatException sffe) { throw new WadDataFormatException(defaultsKey, WadDataFormatException.BAD_RESOURCE_ERROR, sffe, ""); } try { defaultMap = (String)defParser.getSection("Map").keys().nextElement(); } catch (NoSuchElementException nsee) { throw new WadDataFormatException(defaultsKey, WadDataFormatException.BAD_RESOURCE_ERROR, nsee, "defaults.txt must specify a default map"); } if(getMap(defaultMap) == null) { throw new WadDataFormatException(defaultsKey, WadDataFormatException.BAD_RESOURCE_ERROR, "defaults.txt specified a map that doesn't exist" + " in the map wad"); } Hashtable defPlaceNames = defParser.getSection("Places"); if(defPlaceNames != null) { defaultPlaces = new Hashtable(); Enumeration e = defPlaceNames.keys(); while(e.hasMoreElements()) { String placeName = (String)e.nextElement(); Hashtable placeSet = this.getPlaceSet(placeName); if(placeSet == null) { throw new WadDataFormatException(defaultsKey, WadDataFormatException.BAD_RESOURCE_ERROR, "defaults.txt specified a place set that doesn't" + " exist in the map wad"); } defaultPlaces.put(placeName, placeSet); } } else { // there is no requirement to specify default places // a default map is sufficient defaultPlaces = null; } } private void loadMaps() throws IOException, WadDataFormatException { ZipEntry mapIndexEntry = wad.getEntry(mapsIndexKey); if(mapIndexEntry == null || mapIndexEntry.isDirectory()) { // it is not an error to not have any maps in a wad return; } InputStream mapIndexStream = wad.getInputStream(mapIndexEntry); SectionedFileParser indexParser = null; try { indexParser = new SectionedFileParser(mapIndexStream); } catch(SectionedFileFormatException sffe) { throw new WadDataFormatException(mapsIndexKey, WadDataFormatException.BAD_RESOURCE_ERROR, sffe, ""); } Hashtable mapsSection; if((mapsSection = indexParser.getSection("Maps")) == null) { throw new WadDataFormatException(mapsIndexKey, WadDataFormatException.BAD_RESOURCE_ERROR, "No Maps Section"); } Enumeration e = mapsSection.keys(); while(e.hasMoreElements()) { String mapName = (String)e.nextElement(); String metaPath = mapsDirKey + (String)mapsSection.get(mapName); ZipEntry metaEntry = wad.getEntry(metaPath); if(metaEntry == null || metaEntry.isDirectory()) { throw new WadDataFormatException(mapsIndexKey, metaPath, WadDataFormatException.MISSING_RESOURCE_ERROR, metaPath + " doesn't exist, yet it was referenced in " + mapsIndexKey); } MapBacking newMap = loadMapFromEntry(metaEntry, mapName); maps.put(mapName, newMap); } } private MapBacking loadMapFromEntry(ZipEntry entry, String name) throws IOException, WadDataFormatException { // assume that the entry is good, since that should be checked // before i get here InputStream in = wad.getInputStream(entry); SectionedFileParser parser = null; try { parser = new SectionedFileParser(in); } catch (SectionedFileFormatException sffe) { throw new WadDataFormatException(mapsIndexKey, entry.getName(), WadDataFormatException.BAD_RESOURCE_ERROR, sffe, ""); } Hashtable mapHash; if((mapHash = parser.getSection("Map")) == null) { if((mapHash = parser.getSection("TigerMap")) == null) { throw new WadDataFormatException(mapsIndexKey, entry.getName(), WadDataFormatException.BAD_RESOURCE_ERROR, "You must have either a Map section or a TigerMap section"); } else { // parse as a TigerMap String dataPath = getStringOrFail(mapHash, "data", mapsIndexKey, entry.getName()); if(!containsResource(dataPath)) { throw new WadDataFormatException(entry.getName(), dataPath, WadDataFormatException.MISSING_RESOURCE_ERROR, ""); } throw new RuntimeException("Tiger functionality has been temporarily disabled."); //ALM return new TigerMapBacking(name, dataPath, this); } } String imagePath = getStringOrFail(mapHash, "image", mapsIndexKey, entry.getName()); // test that the image at least exists if(!containsResource(imagePath)) { throw new WadDataFormatException(entry.getName(), imagePath, WadDataFormatException.MISSING_RESOURCE_ERROR, ""); } String imageName = basename(imagePath); double originLat = getDoubleOrFail(mapHash, "origin_lat", mapsIndexKey, entry.getName()); double originLon = getDoubleOrFail(mapHash, "origin_lon", mapsIndexKey, entry.getName()); // the two origins scheme is preferable to the pixels_per_lat/lon // scheme, since it is easier on the end user, despite the fact that // it is less efficient. if(mapHash.containsKey("upper_right_lat")) { double upperRightLat = getDoubleOrFail(mapHash, "upper_right_lat", mapsIndexKey, entry.getName()); double upperRightLon = getDoubleOrFail(mapHash, "upper_right_lon", mapsIndexKey, entry.getName()); return new BitmapMapBacking(imageName, imagePath, this, name, originLat, originLon, upperRightLat, upperRightLon); } else { double pixelsPerLat = getDoubleOrFail(mapHash, "pixels_per_lat", mapsIndexKey, entry.getName()); double pixelsPerLon = getDoubleOrFail(mapHash, "pixels_per_lon", mapsIndexKey, entry.getName()); return new BitmapMapBacking(imageName, imagePath, this, originLat,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -