1 /*- 2 * #%L 3 * This file is part of libtiled-java. 4 * %% 5 * Copyright (C) 2004 - 2020 Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> 6 * Copyright (C) 2004 - 2020 Adam Turk <aturk@biggeruniverse.com> 7 * Copyright (C) 2016 - 2020 Mike Thomas <mikepthomas@outlook.com> 8 * %% 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * #L% 30 */ 31 package org.mapeditor.io; 32 33 import java.io.File; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.net.URL; 37 import java.util.List; 38 import java.util.logging.Level; 39 import java.util.logging.Logger; 40 import java.util.zip.GZIPInputStream; 41 42 import javax.xml.bind.JAXBContext; 43 import javax.xml.bind.JAXBElement; 44 import javax.xml.bind.JAXBException; 45 import javax.xml.bind.Unmarshaller; 46 import javax.xml.stream.XMLEventReader; 47 import javax.xml.stream.XMLInputFactory; 48 import javax.xml.stream.XMLStreamException; 49 50 import org.mapeditor.core.Map; 51 import org.mapeditor.core.TileSet; 52 53 /** 54 * The standard map reader for TMX files. Supports reading .tmx, .tmx.gz and 55 * *.tsx files. 56 * 57 * @version 1.4.2 58 */ 59 public class MapReader { 60 61 /** 62 * readMap. 63 * 64 * @param in a {@link java.io.InputStream} object. 65 * @param xmlPath a {@link java.lang.String} object. 66 * @return a {@link org.mapeditor.core.Map} object. 67 * @throws java.io.IOException if any. 68 */ readMap(InputStream in, String xmlPath)69 public Map readMap(InputStream in, String xmlPath) throws IOException { 70 Map unmarshalledMap = unmarshal(in, Map.class); 71 return buildMap(unmarshalledMap, xmlPath); 72 } 73 74 /** 75 * readMap. 76 * 77 * @param filename a {@link java.lang.String} object. 78 * @return a {@link org.mapeditor.core.Map} object. 79 * @throws java.io.IOException if any. 80 */ readMap(String filename)81 public Map readMap(String filename) throws IOException { 82 int fileSeparatorIndex = filename.lastIndexOf(File.separatorChar) + 1; 83 String xmlPath = makeUrl(filename.substring(0, fileSeparatorIndex)); 84 85 String xmlFile = makeUrl(filename); 86 87 URL url = new URL(xmlFile); 88 InputStream is = url.openStream(); 89 90 // Wrap with GZIP decoder for .tmx.gz files 91 if (filename.endsWith(".gz")) { 92 is = new GZIPInputStream(is); 93 } 94 95 return readMap(is, xmlPath); 96 } 97 98 /** 99 * readTileset. 100 * 101 * @param in a {@link java.io.InputStream} object. 102 * @return a {@link org.mapeditor.core.TileSet} object. 103 */ readTileset(InputStream in)104 public TileSet readTileset(InputStream in) { 105 return unmarshal(in, TileSet.class); 106 } 107 108 /** 109 * readTileset. 110 * 111 * @param filename a {@link java.lang.String} object. 112 * @return a {@link org.mapeditor.core.TileSet} object. 113 * @throws java.io.IOException if any. 114 */ readTileset(String filename)115 public TileSet readTileset(String filename) throws IOException { 116 String xmlFile = makeUrl(filename); 117 URL url = new URL(xmlFile); 118 return readTileset(url.openStream()); 119 } 120 buildMap(Map map, String xmlPath)121 private Map buildMap(Map map, String xmlPath) throws IOException { 122 List<TileSet> tilesets = map.getTileSets(); 123 for (int i = 0; i < tilesets.size(); i++) { 124 TileSet tileset = tilesets.get(i); 125 String tileSetSource = tileset.getSource(); 126 if (tileSetSource != null) { 127 int firstGid = tileset.getFirstgid(); 128 tileset = readTileset(xmlPath + tileSetSource); 129 tileset.setFirstgid(firstGid); 130 tileset.setSource(tileSetSource); 131 tilesets.set(i, tileset); 132 } 133 } 134 return map; 135 } 136 makeUrl(String filename)137 private String makeUrl(String filename) { 138 final String url; 139 if (filename.indexOf("://") > 0 || filename.startsWith("file:")) { 140 url = filename; 141 } else { 142 url = new File(filename).toURI().toString(); 143 } 144 return url; 145 } 146 unmarshal(InputStream in, Class<T> type)147 private <T> T unmarshal(InputStream in, Class<T> type) { 148 try { 149 XMLInputFactory factory = XMLInputFactory.newInstance(); 150 XMLEventReader reader = factory.createXMLEventReader(in); 151 152 JAXBContext context = JAXBContext.newInstance(type); 153 Unmarshaller unmarshaller = context.createUnmarshaller(); 154 155 JAXBElement<T> element = unmarshaller.unmarshal(reader, type); 156 return element.getValue(); 157 } catch (XMLStreamException | JAXBException ex) { 158 Logger.getLogger(MapReader.class.getName()).log(Level.SEVERE, null, ex); 159 return null; 160 } 161 } 162 } 163