001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.io.BufferedReader; 005import java.io.IOException; 006import java.net.URL; 007 008import org.openstreetmap.josm.Main; 009import org.openstreetmap.josm.spi.preferences.Config; 010import org.openstreetmap.josm.tools.LanguageInfo.LocaleType; 011 012/** 013 * Read a trac-wiki page. 014 * 015 * @author imi 016 */ 017public class WikiReader { 018 019 private final String baseurl; 020 021 /** 022 * Constructs a new {@code WikiReader} for the given base URL. 023 * @param baseurl The wiki base URL 024 */ 025 public WikiReader(String baseurl) { 026 this.baseurl = baseurl; 027 } 028 029 /** 030 * Constructs a new {@code WikiReader}. 031 */ 032 public WikiReader() { 033 this(Config.getPref().get("help.baseurl", Main.getJOSMWebsite())); 034 } 035 036 /** 037 * Returns the base URL of wiki. 038 * @return the base URL of wiki 039 * @since 7434 040 */ 041 public final String getBaseUrlWiki() { 042 return baseurl + "/wiki/"; 043 } 044 045 /** 046 * Read the page specified by the url and return the content. 047 * 048 * If the url is within the baseurl path, parse it as an trac wikipage and replace relative paths etc.. 049 * @param url the URL to read 050 * @return The page as string 051 * 052 * @throws IOException Throws, if the page could not be loaded. 053 */ 054 public String read(String url) throws IOException { 055 URL u = new URL(url); 056 try (BufferedReader in = HttpClient.create(u).connect().getContentReader()) { 057 boolean txt = url.endsWith("?format=txt"); 058 if (url.startsWith(getBaseUrlWiki()) && !txt) 059 return readFromTrac(in, u); 060 return readNormal(in, !txt); 061 } 062 } 063 064 /** 065 * Reads the localized version of the given wiki page. 066 * @param text The page title, without locale prefix 067 * @return the localized version of the given wiki page 068 * @throws IOException if any I/O error occurs 069 */ 070 public String readLang(String text) throws IOException { 071 String languageCode; 072 String res = ""; 073 074 languageCode = LanguageInfo.getWikiLanguagePrefix(LocaleType.DEFAULTNOTENGLISH); 075 if (languageCode != null) { 076 res = readLang(new URL(getBaseUrlWiki() + languageCode + text)); 077 } 078 079 if (res.isEmpty()) { 080 languageCode = LanguageInfo.getWikiLanguagePrefix(LocaleType.BASELANGUAGE); 081 if (languageCode != null) { 082 res = readLang(new URL(getBaseUrlWiki() + languageCode + text)); 083 } 084 } 085 086 if (res.isEmpty()) { 087 languageCode = LanguageInfo.getWikiLanguagePrefix(LocaleType.ENGLISH); 088 if (languageCode != null) { 089 res = readLang(new URL(getBaseUrlWiki() + languageCode + text)); 090 } 091 } 092 093 if (res.isEmpty()) { 094 throw new IOException(text + " does not exist"); 095 } else { 096 return res; 097 } 098 } 099 100 private String readLang(URL url) throws IOException { 101 try (BufferedReader in = HttpClient.create(url).connect().getContentReader()) { 102 return readFromTrac(in, url); 103 } 104 } 105 106 private static String readNormal(BufferedReader in, boolean html) throws IOException { 107 StringBuilder b = new StringBuilder(); 108 for (String line = in.readLine(); line != null; line = in.readLine()) { 109 if (!line.contains("[[TranslatedPages]]")) { 110 b.append(line.replaceAll(" />", ">")).append('\n'); 111 } 112 } 113 return html ? "<html>" + b + "</html>" : b.toString(); 114 } 115 116 protected String readFromTrac(BufferedReader in, URL url) throws IOException { 117 boolean inside = false; 118 boolean transl = false; 119 boolean skip = false; 120 StringBuilder b = new StringBuilder(); 121 StringBuilder full = new StringBuilder(); 122 for (String line = in.readLine(); line != null; line = in.readLine()) { 123 full.append(line); 124 if (line.contains("<div id=\"searchable\">")) { 125 inside = true; 126 } else if (line.contains("<div class=\"wiki-toc trac-nav\"")) { 127 transl = true; 128 } else if (line.contains("<div class=\"wikipage searchable\">")) { 129 inside = true; 130 } else if (line.contains("<div class=\"buttons\">")) { 131 inside = false; 132 } else if (line.contains("<h3>Attachments</h3>")) { 133 inside = false; 134 } else if (line.contains("<div id=\"attachments\">")) { 135 inside = false; 136 } else if (line.contains("<div class=\"trac-modifiedby\">")) { 137 skip = true; 138 } 139 if (inside && !transl && !skip) { 140 // add a border="0" attribute to images, otherwise the internal help browser 141 // will render a thick border around images inside an <a> element 142 // remove width information to avoid distorded images (fix #11262) 143 b.append(line.replaceAll("<img ", "<img border=\"0\" ") 144 .replaceAll("width=\"(\\d+)\"", "") 145 .replaceAll("<span class=\"icon\">.</span>", "") 146 .replaceAll("href=\"/", "href=\"" + baseurl + '/') 147 .replaceAll(" />", ">")) 148 .append('\n'); 149 } else if (transl && line.contains("</div>")) { 150 transl = false; 151 } 152 if (line.contains("</div>")) { 153 skip = false; 154 } 155 } 156 if (b.indexOf(" Describe ") >= 0 157 || b.indexOf(" does not exist. You can create it here.</p>") >= 0) 158 return ""; 159 if (b.length() == 0) 160 b = full; 161 return "<html><base href=\""+url.toExternalForm() +"\"> " + b + "</html>"; 162 } 163}