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