mirror of
https://github.com/yacy/yacy_search_server.git
synced 2024-09-21 00:00:13 +02:00
0edec2b760
The old process used a not really efficient way to detect html encoding strings in texts. All calling methods had been adoped to call the new class in an enhanced way with less parameters. Many classes in interfaces used a XML encoding only (instead of full html conversion from unicode to html); this behavior was not changed with this commit but should be controlled again since it points out possible XSS leaks git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@5295 6c8d7289-2bf4-0310-a012-ef5d649a1542
820 lines
38 KiB
Java
820 lines
38 KiB
Java
// wikiCode.java
|
|
// -------------------------------------
|
|
// part of YACY
|
|
//
|
|
// (C) 2005, 2006 by Alexander Schier
|
|
// Marc Nause, Franz Brausze
|
|
//
|
|
//
|
|
// last change: $LastChangedDate: $ by $LastChangedBy: $
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
// Contains contributions from Alexander Schier [AS]
|
|
// Franz Brausze [FB] and Marc Nause [MN]
|
|
|
|
package de.anomic.data;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
|
|
import de.anomic.data.wiki.abstractWikiParser;
|
|
import de.anomic.data.wiki.wikiParser;
|
|
import de.anomic.htmlFilter.htmlFilterCharacterCoding;
|
|
import de.anomic.plasma.plasmaSwitchboard;
|
|
import de.anomic.server.serverCore;
|
|
|
|
/** This class provides methods to handle texts that have been posted in the yacyWiki or other
|
|
* parts of YaCy that use this class, like the blog or the profile.
|
|
*/
|
|
public class wikiCode extends abstractWikiParser implements wikiParser {
|
|
|
|
/* Table properties */
|
|
private static final String[] tps = { "rowspan", "colspan", "vspace", "hspace", "cellspacing", "cellpadding", "border" };
|
|
private static final HashMap/* <String,String[]> */<String, String[]> ps = new HashMap<String, String[]>();
|
|
static {
|
|
Arrays.sort(tps);
|
|
String[] array;
|
|
Arrays.sort(array = new String[] { "void", "above", "below", "hsides", "lhs", "rhs", "vsides", "box", "border" });
|
|
ps.put("frame", array);
|
|
Arrays.sort(array = new String[] { "none", "groups", "rows", "cols", "all" });
|
|
ps.put("rules", array);
|
|
Arrays.sort(array = new String[] { "top", "middle", "bottom", "baseline" });
|
|
ps.put("valign", array);
|
|
Arrays.sort(array = new String[] { "left", "right", "center" });
|
|
ps.put("align", array);
|
|
}
|
|
|
|
private String numListLevel="";
|
|
private String ListLevel="";
|
|
private String defListLevel="";
|
|
private boolean cellprocessing=false; //needed for prevention of double-execution of replaceHTML
|
|
private boolean defList = false; //needed for definition lists
|
|
private boolean escape = false; //needed for escape
|
|
private boolean escaped = false; //needed for <pre> not getting in the way
|
|
private boolean escapeSpan = false; //needed for escape symbols [= and =] spanning over several lines
|
|
private boolean newrowstart=false; //needed for the first row not to be empty
|
|
private boolean nolist = false; //needed for handling of [= and <pre> in lists
|
|
private boolean preformatted = false; //needed for preformatted text
|
|
private boolean preformattedSpan = false; //needed for <pre> and </pre> spanning over several lines
|
|
private boolean replacedHTML = false; //indicates if method replaceHTML has been used with line already
|
|
private boolean table = false; //needed for tables, because they reach over several lines
|
|
private int preindented = 0; //needed for indented <pre>s
|
|
private int escindented = 0; //needed for indented [=s
|
|
private int headlines = 0; //number of headlines in page
|
|
private final ArrayList<String> dirElements = new ArrayList<String>(); //list of headlines used to create diectory of page
|
|
|
|
/** Constructor of the class wikiCode */
|
|
public wikiCode(final plasmaSwitchboard switchboard){
|
|
super(switchboard);
|
|
}
|
|
|
|
protected String transform(
|
|
final BufferedReader reader,
|
|
final int length,
|
|
final String publicAddress,
|
|
final plasmaSwitchboard switchboard) throws IOException {
|
|
final StringBuffer out = new StringBuffer(length);
|
|
String line;
|
|
while ((line = reader.readLine()) != null)
|
|
out.append(transformLine(line, publicAddress, switchboard)).append(serverCore.CRLF_STRING);
|
|
return out.insert(0, directory()).toString();
|
|
}
|
|
|
|
/** This method processes tables in the wiki code.
|
|
* @param a string that might contain parts of a table
|
|
* @return a string with wiki code of parts of table replaced by HTML code for table
|
|
*/
|
|
//[FB], changes by [MN]
|
|
private String processTable(String result, final plasmaSwitchboard switchboard){
|
|
//some variables that make it easier to change codes for the table
|
|
String line = "";
|
|
final String tableStart = "{|"; // {|
|
|
final String newLine = "|-"; // |-
|
|
final String cellDivider = "||"; // ||
|
|
final String tableEnd = "|}"; // |}
|
|
final String attribDivider = "|"; // |
|
|
final int lenTableStart = tableStart.length();
|
|
final int lenCellDivider = cellDivider.length();
|
|
final int lenTableEnd = tableEnd.length();
|
|
final int lenAttribDivider = attribDivider.length();
|
|
|
|
if ((result.startsWith(tableStart)) && (!table)) {
|
|
table=true;
|
|
newrowstart=true;
|
|
line="<table";
|
|
if (result.trim().length()>lenTableStart) {
|
|
line+=parseTableProperties(result.substring(lenTableStart).trim()).toString();
|
|
}
|
|
line+=">";
|
|
result=line;
|
|
}
|
|
else if (result.startsWith(newLine) && (table)) { // new row
|
|
if (!newrowstart) {
|
|
line+="\t</tr>\n";
|
|
} else {
|
|
newrowstart=false;
|
|
}
|
|
line=line+"\t<tr>";
|
|
result=line;
|
|
}
|
|
else if ((result.startsWith(cellDivider)) && (table)) {
|
|
line+="\t\t<td";
|
|
final int cellEnd=(result.indexOf(cellDivider,lenCellDivider)>0)?(result.indexOf(cellDivider,lenCellDivider)):(result.length());
|
|
int propEnd = result.indexOf(attribDivider,lenCellDivider);
|
|
final int occImage = result.indexOf("[[Image:",lenCellDivider);
|
|
final int occEscape = result.indexOf("[=",lenCellDivider);
|
|
//If resultOf("[[Image:") is less than propEnd, that means that there is no
|
|
//property for this cell, only an image. Without this, YaCy could get confused
|
|
//by a | in [[Image:picture.png|alt-text]] or [[Image:picture.png|alt-text]]
|
|
//Same for [= (part of [= =])
|
|
if((propEnd > lenCellDivider)
|
|
&&((occImage > propEnd)||( occImage < 0))
|
|
&&((occEscape> propEnd)||( occEscape < 0))
|
|
){
|
|
propEnd = result.indexOf(attribDivider,lenCellDivider)+lenAttribDivider;
|
|
}
|
|
else {
|
|
propEnd = cellEnd;
|
|
}
|
|
// both point at same place => new line
|
|
if (propEnd==cellEnd) {
|
|
propEnd=lenCellDivider;
|
|
}
|
|
else {
|
|
line+=parseTableProperties(result.substring(lenCellDivider,propEnd-lenAttribDivider).trim()).toString();
|
|
}
|
|
// quick&dirty fix [MN]
|
|
if(propEnd > cellEnd){
|
|
propEnd = lenCellDivider;
|
|
}
|
|
table=false; cellprocessing=true;
|
|
line+=">"+processTable(result.substring(propEnd,cellEnd).trim(), switchboard)+"</td>";
|
|
table=true; cellprocessing=false;
|
|
if (cellEnd<result.length()) {
|
|
line+="\n"+processTable(result.substring(cellEnd), switchboard);
|
|
}
|
|
result=line;
|
|
}
|
|
else if (result.startsWith(tableEnd) && (table)) { // Table end
|
|
table=false;
|
|
line+="\t</tr>\n</table>"+result.substring(lenTableEnd);
|
|
result=line;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// contributed by [MN], changes by [FB]
|
|
/** This method takes possible table properties and tests if they are valid.
|
|
* Valid in this case means if they are a property for the table, tr or td
|
|
* tag as stated in the HTML Pocket Reference by Jennifer Niederst (1st edition)
|
|
* The method is important to avoid XSS attacks on the wiki via table properties.
|
|
* @param properties A string that may contain several table properties and/or junk.
|
|
* @return A string that only contains table properties.
|
|
*/
|
|
private static StringBuffer parseTableProperties(final String properties) {
|
|
final String[] values = properties.replaceAll(""", "").split("[= ]"); //splitting the string at = and blanks
|
|
final StringBuffer sb = new StringBuffer(properties.length());
|
|
String key, value;
|
|
String[] posVals;
|
|
final int numberofvalues = values.length;
|
|
for (int i=0; i<numberofvalues; i++) {
|
|
key = values[i].trim();
|
|
if (key.equals("nowrap")) {
|
|
addPair("nowrap", "nowrap", sb);
|
|
} else if (i + 1 < numberofvalues) {
|
|
value = values[++i].trim();
|
|
if (
|
|
(key.equals("summary")) ||
|
|
(key.equals("bgcolor") && value.matches("#{0,1}[0-9a-fA-F]{1,6}|[a-zA-Z]{3,}")) ||
|
|
((key.equals("width") || key.equals("height")) && value.matches("\\d+%{0,1}")) ||
|
|
((posVals = ps.get(key)) != null && Arrays.binarySearch(posVals, value) >= 0) ||
|
|
(Arrays.binarySearch(tps, key) >= 0 && value.matches("\\d+"))
|
|
) {
|
|
addPair(key, value, sb);
|
|
}
|
|
}
|
|
}
|
|
return sb;
|
|
}
|
|
|
|
private static StringBuffer addPair(final String key, final String value, final StringBuffer sb) {
|
|
return sb.append(" ").append(key).append("=\"").append(value).append("\"");
|
|
}
|
|
|
|
/** This method processes ordered lists.
|
|
*/
|
|
private String orderedList(String result){
|
|
if(!nolist){ //lists only get processed if not forbidden (see code for [= and <pre>). [MN]
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
//# sorted Lists contributed by [AS]
|
|
//## Sublist
|
|
if(result.startsWith(numListLevel + "#")){ //more #
|
|
p0 = result.indexOf(numListLevel);
|
|
p1 = result.length();
|
|
result = "<ol>" + serverCore.CRLF_STRING +
|
|
"<li>" +
|
|
result.substring(numListLevel.length() + 1, p1) +
|
|
"</li>";
|
|
numListLevel += "#";
|
|
}else if(numListLevel.length() > 0 && result.startsWith(numListLevel)){ //equal number of #
|
|
p0 = result.indexOf(numListLevel);
|
|
p1 = result.length();
|
|
result = "<li>" +
|
|
result.substring(numListLevel.length(), p1) +
|
|
"</li>";
|
|
}else if(numListLevel.length() > 0){ //less #
|
|
int i = numListLevel.length();
|
|
String tmp = "";
|
|
|
|
while(! result.startsWith(numListLevel.substring(0,i)) ){
|
|
tmp += "</ol>";
|
|
i--;
|
|
}
|
|
numListLevel = numListLevel.substring(0,i);
|
|
p0 = numListLevel.length();
|
|
p1 = result.length();
|
|
|
|
if(numListLevel.length() > 0){
|
|
result = tmp +
|
|
"<li>" +
|
|
result.substring(p0, p1) +
|
|
"</li>";
|
|
}else{
|
|
result = tmp + result.substring(p0, p1);
|
|
}
|
|
}
|
|
// end contrib [AS]
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** This method processes unordered lists.
|
|
*/
|
|
//contributed by [AS] put into it's own method by [MN]
|
|
private String unorderedList(String result){
|
|
if(!nolist){ //lists only get processed if not forbidden (see code for [= and <pre>). [MN]
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
//contributed by [AS]
|
|
if(result.startsWith(ListLevel + "*")){ //more stars
|
|
p0 = result.indexOf(ListLevel);
|
|
p1 = result.length();
|
|
result = "<ul>" + serverCore.CRLF_STRING +
|
|
"<li>" +
|
|
result.substring(ListLevel.length() + 1, p1) +
|
|
"</li>";
|
|
ListLevel += "*";
|
|
}else if(ListLevel.length() > 0 && result.startsWith(ListLevel)){ //equal number of stars
|
|
p0 = result.indexOf(ListLevel);
|
|
p1 = result.length();
|
|
result = "<li>" +
|
|
result.substring(ListLevel.length(), p1) +
|
|
"</li>";
|
|
}else if(ListLevel.length() > 0){ //less stars
|
|
int i = ListLevel.length();
|
|
String tmp = "";
|
|
|
|
while(! result.startsWith(ListLevel.substring(0,i))){
|
|
tmp += "</ul>";
|
|
i--;
|
|
}
|
|
ListLevel = ListLevel.substring(0,i);
|
|
p0 = ListLevel.length();
|
|
p1 = result.length();
|
|
|
|
if(ListLevel.length() > 0){
|
|
result = tmp +
|
|
"<li>" +
|
|
result.substring(p0, p1) +
|
|
"</li>";
|
|
}else{
|
|
result = tmp + result.substring(p0, p1);
|
|
}
|
|
}
|
|
//end contrib [AS]
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** This method processes definition lists.
|
|
*/
|
|
//contributed by [MN] based on unordered list code by [AS]
|
|
private String definitionList(String result){
|
|
if(!nolist){ //lists only get processed if not forbidden (see code for [= and <pre>). [MN]
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
if(result.startsWith(defListLevel + ";")){ //more semicolons
|
|
String dt = "";
|
|
String dd = "";
|
|
p0 = result.indexOf(defListLevel);
|
|
p1 = result.length();
|
|
final String resultCopy = result.substring(defListLevel.length() + 1, p1);
|
|
if((p0 = resultCopy.indexOf(":")) > 0){
|
|
dt = resultCopy.substring(0,p0);
|
|
dd = resultCopy.substring(p0+1);
|
|
result = "<dl>" + "<dt>" + dt + "</dt>" + "<dd>" + dd;
|
|
defList = true;
|
|
}
|
|
defListLevel += ";";
|
|
}else if(defListLevel.length() > 0 && result.startsWith(defListLevel)){ //equal number of semicolons
|
|
String dt = "";
|
|
String dd = "";
|
|
p0 = result.indexOf(defListLevel);
|
|
p1 = result.length();
|
|
final String resultCopy = result.substring(defListLevel.length(), p1);
|
|
if((p0 = resultCopy.indexOf(":")) > 0){
|
|
dt = resultCopy.substring(0,p0);
|
|
dd = resultCopy.substring(p0+1);
|
|
result = "<dt>" + dt + "</dt>" + "<dd>" + dd;
|
|
defList = true;
|
|
}
|
|
}else if(defListLevel.length() > 0){ //less semicolons
|
|
String dt = "";
|
|
String dd = "";
|
|
int i = defListLevel.length();
|
|
String tmp = "";
|
|
while(! result.startsWith(defListLevel.substring(0,i)) ){
|
|
tmp += "</dd></dl>";
|
|
i--;
|
|
}
|
|
defListLevel = defListLevel.substring(0,i);
|
|
p0 = defListLevel.length();
|
|
p1 = result.length();
|
|
if(defListLevel.length() > 0){
|
|
final String resultCopy = result.substring(p0, p1);
|
|
if((p0 = resultCopy.indexOf(":")) > 0){
|
|
dt = resultCopy.substring(0,p0);
|
|
dd = resultCopy.substring(p0+1);
|
|
result = tmp + "<dt>" + dt + "</dt>" + "<dd>" + dd;
|
|
defList = true;
|
|
}
|
|
}else{
|
|
result = tmp + result.substring(p0, p1);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** This method processes links and images.
|
|
*/
|
|
//contributed by [AS] except where stated otherwise
|
|
private String linksAndImages(String result, final String publicAddress, final plasmaSwitchboard switchboard) {
|
|
|
|
// create links
|
|
String kl, kv, alt, align;
|
|
int p;
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
// internal links and images
|
|
while ((p0 = result.indexOf("[[")) >= 0) {
|
|
p1 = result.indexOf("]]", p0 + 2);
|
|
if (p1 <= p0) break;
|
|
kl = result.substring(p0 + 2, p1);
|
|
|
|
// this is the part of the code that's responsible for images
|
|
// contributed by [MN]
|
|
if (kl.startsWith("Image:")) {
|
|
alt = "";
|
|
align = "";
|
|
kv = "";
|
|
kl = kl.substring(6);
|
|
|
|
// are there any arguments for the image?
|
|
if ((p = kl.indexOf("|")) > 0) {
|
|
kv = kl.substring(p + 6);
|
|
kl = kl.substring(0, p);
|
|
// if there are 2 arguments, write them into ALIGN and ALT
|
|
if ((p = kv.indexOf("|")) > 0) {
|
|
align = kv.substring(0, p);
|
|
//checking validity of value for align. Only non browser specific
|
|
//values get supported. Not supported: absmiddle, baseline, texttop
|
|
if ((align.equals("bottom"))||
|
|
(align.equals("center"))||
|
|
(align.equals("left"))||
|
|
(align.equals("middle"))||
|
|
(align.equals("right"))||
|
|
(align.equals("top")))
|
|
{
|
|
align = " align=\"" + align + "\"";
|
|
}
|
|
else align = "";
|
|
alt = " alt=\"" + kv.substring(p + 6) + "\"";
|
|
}
|
|
// if there is just one, put it into ALT
|
|
else
|
|
alt = " alt=\"" + kv + "\"";
|
|
}
|
|
|
|
// replace incomplete URLs and make them point to http://peerip:port/...
|
|
// with this feature you can access an image in DATA/HTDOCS/share/yacy.gif
|
|
// using the wikicode [[Image:share/yacy.gif]]
|
|
// or an image DATA/HTDOCS/grafics/kaskelix.jpg with [[Image:grafics/kaskelix.jpg]]
|
|
// you are free to use other sub-paths of DATA/HTDOCS
|
|
if (kl.indexOf("://")<1) {
|
|
kl = "http://" + publicAddress.trim() + "/" + kl;
|
|
}
|
|
|
|
result = result.substring(0, p0) + "<img src=\"" + kl + "\"" + align + alt + ">" + result.substring(p1 + 2);
|
|
}
|
|
// end contrib [MN]
|
|
|
|
// if it's no image, it might be an internal link
|
|
else {
|
|
if ((p = kl.indexOf("|")) > 0) {
|
|
kv = kl.substring(p + 6);
|
|
kl = kl.substring(0, p);
|
|
} else {
|
|
kv = kl;
|
|
}
|
|
if (switchboard != null && switchboard.wikiDB.read(kl) != null) {
|
|
result = result.substring(0, p0) + "<a class=\"known\" href=\"Wiki.html?page=" + kl + "\">" + kv + "</a>" + result.substring(p1 + 2);
|
|
} else {
|
|
result = result.substring(0, p0) + "<a class=\"unknown\" href=\"Wiki.html?page=" + kl + "&edit=Edit\">" + kv + "</a>" + result.substring(p1 + 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// external links
|
|
while ((p0 = result.indexOf("[")) >= 0) {
|
|
p1 = result.indexOf("]", p0 + 1);
|
|
if (p1 <= p0) break;
|
|
kl = result.substring(p0 + 1, p1);
|
|
if ((p = kl.indexOf(" ")) > 0) {
|
|
kv = kl.substring(p + 1);
|
|
kl = kl.substring(0, p);
|
|
}
|
|
// No text for the link? -> <a href="http://www.url.com/">http://www.url.com/</a>
|
|
else {
|
|
kv = kl;
|
|
}
|
|
// replace incomplete URLs and make them point to http://peerip:port/...
|
|
// with this feature you can access a file at DATA/HTDOCS/share/page.html
|
|
// using the wikicode [share/page.html]
|
|
// or a file DATA/HTDOCS/www/page.html with [www/page.html]
|
|
// you are free to use other sub-paths of DATA/HTDOCS
|
|
if (kl.indexOf("://") < 1) {
|
|
kl = "http://" + publicAddress.trim() + "/" + kl;
|
|
}
|
|
result = result.substring(0, p0) + "<a class=\"extern\" href=\"" + kl + "\">" + kv + "</a>" + result.substring(p1 + 1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** This method handles the escape tags [= =] */
|
|
//contributed by [MN]
|
|
private String escapeTag(String result, final String publicAddress, final plasmaSwitchboard switchboard){
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
//both [= and =] in the same line
|
|
if(((p0 = result.indexOf("[="))>=0)&&((p1 = result.indexOf("=]"))>0)&&(!(preformatted))){
|
|
if(p0<p1){
|
|
String escapeText = result.substring(p0+2,p1);
|
|
escapeText = escapeText.replaceAll("!esc!", "!esc!!");
|
|
result = transformLine(result.substring(0,p0).replaceAll("!esc!", "!esc!!")+"!esc!txt!"+result.substring(p1+2).replaceAll("!esc!", "!esc!!"), publicAddress, switchboard);
|
|
result = result.replaceAll("!esc!txt!", escapeText);
|
|
result = result.replaceAll("!esc!!", "!esc!");
|
|
}
|
|
//handles cases like [=[= =]=] [= =] that would cause an exception otherwise
|
|
else{
|
|
escape = true;
|
|
final String temp1 = transformLine(result.substring(0,p0-1).replaceAll("!tmp!","!tmp!!")+"!tmp!txt!", publicAddress, switchboard);
|
|
nolist = true;
|
|
final String temp2 = transformLine(result.substring(p0), publicAddress, switchboard);
|
|
nolist = false;
|
|
result = temp1.replaceAll("!tmp!txt!",temp2);
|
|
result = result.replaceAll("!tmp!!", "!tmp!");
|
|
escape = false;
|
|
}
|
|
}
|
|
|
|
//start [=
|
|
else if(((p0 = result.indexOf("[="))>=0)&&(!escapeSpan)&&(!preformatted)){
|
|
escape = true; //prevent surplus line breaks
|
|
escaped = true; //prevents <pre> being parsed
|
|
String bq = ""; //gets filled with <blockquote>s as needed
|
|
String escapeText = result.substring(p0+2);
|
|
escapeText = escapeText.replaceAll("!esc!", "!esc!!");
|
|
//taking care of indented lines
|
|
while(result.substring(escindented,p0).startsWith(":")){
|
|
escindented++;
|
|
bq = bq + "<blockquote>";
|
|
}
|
|
result = transformLine(result.substring(escindented,p0).replaceAll("!esc!", "!esc!!")+"!esc!txt!", publicAddress, switchboard);
|
|
result = bq + result.replaceAll("!esc!txt!", escapeText);
|
|
result = result.replaceAll("!esc!!", "!esc!");
|
|
escape = false;
|
|
escapeSpan = true;
|
|
}
|
|
|
|
//end =]
|
|
else if(((p0 = result.indexOf("=]"))>=0)&&(escapeSpan)&&(!preformatted)){
|
|
escapeSpan = false;
|
|
String bq = ""; //gets filled with </blockquote>s as needed
|
|
String escapeText = result.substring(0,p0);
|
|
escapeText = escapeText.replaceAll("!esc!", "!esc!!");
|
|
//taking care of indented lines
|
|
while(escindented > 0){
|
|
bq = bq + "</blockquote>";
|
|
escindented--;
|
|
}
|
|
result = transformLine("!esc!txt!"+result.substring(p0+2).replaceAll("!esc!", "!esc!!"), publicAddress, switchboard);
|
|
result = result.replaceAll("!esc!txt!", escapeText) + bq;
|
|
result = result.replaceAll("!esc!!", "!esc!");
|
|
escaped = false;
|
|
}
|
|
//Getting rid of surplus =]
|
|
else if (((p0 = result.indexOf("=]"))>=0)&&(!escapeSpan)&&(!preformatted)){
|
|
while((p0 = result.indexOf("=]"))>=0){
|
|
result = result.substring(0,p0)+result.substring(p0+2);
|
|
}
|
|
result = transformLine(result, publicAddress, switchboard);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** This method handles the preformatted tags <pre> </pre> */
|
|
//contributed by [MN]
|
|
private String preformattedTag(String result, final String publicAddress, final plasmaSwitchboard switchboard){
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
//implementation very similar to escape code (see above)
|
|
//both <pre> and </pre> in the same line
|
|
if(((p0=result.indexOf("<pre>"))>=0)&&((p1=result.indexOf("</pre>"))>0)&&(!(escaped))){
|
|
if(p0<p1){
|
|
String preformattedText = "<pre style=\"border:dotted;border-width:thin\">"+result.substring(p0+11,p1)+"</pre>";
|
|
preformattedText = preformattedText.replaceAll("!pre!", "!pre!!");
|
|
result = transformLine(result.substring(0,p0).replaceAll("!pre!", "!pre!!")+"!pre!txt!"+result.substring(p1+12).replaceAll("!pre!", "!pre!!"), publicAddress, switchboard);
|
|
result = result.replaceAll("!pre!txt!", preformattedText);
|
|
result = result.replaceAll("!pre!!", "!pre!");
|
|
}
|
|
//handles cases like <pre><pre> </pre></pre> <pre> </pre> that would cause an exception otherwise
|
|
else{
|
|
preformatted = true;
|
|
final String temp1 = transformLine(result.substring(0,p0-1).replaceAll("!tmp!","!tmp!!")+"!tmp!txt!", publicAddress, switchboard);
|
|
nolist = true;
|
|
final String temp2 = transformLine(result.substring(p0), publicAddress, switchboard);
|
|
nolist = false;
|
|
result = temp1.replaceAll("!tmp!txt!",temp2);
|
|
result = result.replaceAll("!tmp!!", "!tmp!");
|
|
preformatted = false;
|
|
}
|
|
}
|
|
|
|
//start <pre>
|
|
else if(((p0 = result.indexOf("<pre>"))>=0)&&(!preformattedSpan)&&(!escaped)){
|
|
preformatted = true; //prevent surplus line breaks
|
|
String bq =""; //gets filled with <blockquote>s as needed
|
|
String preformattedText = "<pre style=\"border:dotted;border-width:thin\">"+result.substring(p0+11);
|
|
preformattedText = preformattedText.replaceAll("!pre!", "!pre!!");
|
|
//taking care of indented lines
|
|
while(result.substring(preindented,p0).startsWith(":")){
|
|
preindented++;
|
|
bq = bq + "<blockquote>";
|
|
}
|
|
result = transformLine(result.substring(preindented,p0).replaceAll("!pre!", "!pre!!")+"!pre!txt!", publicAddress, switchboard);
|
|
result = bq + result.replaceAll("!pre!txt!", preformattedText);
|
|
result = result.replaceAll("!pre!!", "!pre!");
|
|
preformattedSpan = true;
|
|
}
|
|
|
|
//end </pre>
|
|
else if(((p0 = result.indexOf("</pre>"))>=0)&&(preformattedSpan)&&(!escaped)){
|
|
preformattedSpan = false;
|
|
String bq = ""; //gets filled with </blockquote>s as needed
|
|
String preformattedText = result.substring(0,p0)+"</pre>";
|
|
preformattedText = preformattedText.replaceAll("!pre!", "!pre!!");
|
|
//taking care of indented lines
|
|
while (preindented > 0){
|
|
bq = bq + "</blockquote>";
|
|
preindented--;
|
|
}
|
|
result = transformLine("!pre!txt!"+result.substring(p0+12).replaceAll("!pre!", "!pre!!"), publicAddress, switchboard);
|
|
result = result.replaceAll("!pre!txt!", preformattedText) + bq;
|
|
result = result.replaceAll("!pre!!", "!pre!");
|
|
preformatted = false;
|
|
}
|
|
//Getting rid of surplus </pre>
|
|
else if (((p0 = result.indexOf("</pre>"))>=0)&&(!preformattedSpan)&&(!escaped)){
|
|
while((p0 = result.indexOf("</pre>"))>=0){
|
|
result = result.substring(0,p0)+result.substring(p0+12);
|
|
}
|
|
result = transformLine(result, publicAddress, switchboard);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** This method creates a directory for a wiki page.
|
|
* @return directory of the wiki
|
|
*/
|
|
//method contributed by [MN]
|
|
private String directory(){
|
|
String directory = "";
|
|
String element;
|
|
int s = 0;
|
|
int level = 1;
|
|
int level1 = 0;
|
|
int level2 = 0;
|
|
int level3 = 0;
|
|
int doubles = 0;
|
|
String anchorext = "";
|
|
if((s=dirElements.size())>2){
|
|
for(int i=0;i<s;i++){
|
|
element = dirElements.get(i);
|
|
//counting double headlines
|
|
doubles = 0;
|
|
for(int j=0;j<i;j++){
|
|
if(dirElements.get(j).substring(1).replaceAll(" ","_").replaceAll("[^a-zA-Z0-9_]","").equals(element.substring(1).replaceAll(" ","_").replaceAll("[^a-zA-Z0-9_]",""))){
|
|
doubles++;
|
|
}
|
|
}
|
|
//if there are doubles, create anchorextension
|
|
if(doubles>0){
|
|
anchorext = "_" + (doubles+1);
|
|
}
|
|
|
|
if (element.startsWith("3")){
|
|
if(level<3){
|
|
level = 3;
|
|
level3 = 0;
|
|
}
|
|
level3++;
|
|
final String temp = element.substring(1);
|
|
element=level1+"."+level2+"."+level3+" "+temp;
|
|
directory = directory + " <a href=\"#"+temp.replaceAll(" ","_").replaceAll("[^a-zA-Z0-9_]","")+anchorext+"\" class=\"WikiTOC\">"+element+"</a><br />\n";
|
|
}
|
|
else if (element.startsWith("2")){
|
|
if(level==1){
|
|
level2 = 0;
|
|
level = 2;
|
|
}
|
|
if(level==3){
|
|
level = 2;
|
|
}
|
|
level2++;
|
|
final String temp = element.substring(1);
|
|
element=level1+"."+level2+" "+temp;
|
|
directory = directory + " <a href=\"#"+temp.replaceAll(" ","_").replaceAll("[^a-zA-Z0-9_]","")+anchorext+"\" class=\"WikiTOC\">"+element+"</a><br />\n";
|
|
}
|
|
else if (element.startsWith("1")) {
|
|
if (level>1) {
|
|
level = 1;
|
|
level2 = 0;
|
|
level3 = 0;
|
|
}
|
|
level1++;
|
|
final String temp = element.substring(1);
|
|
element=level1+". "+temp;
|
|
directory = directory + "<a href=\"#"+temp.replaceAll(" ","_").replaceAll("[^a-zA-Z0-9_]","")+anchorext+"\" class=\"WikiTOC\">"+element+"</a><br />\n";
|
|
}
|
|
anchorext="";
|
|
}
|
|
directory = "<table><tr><td><div class=\"WikiTOCBox\">\n" + directory + "</div></td></tr></table>\n";
|
|
}
|
|
// [MN]
|
|
if(!dirElements.isEmpty()){
|
|
dirElements.clear();
|
|
headlines = 0;
|
|
}
|
|
return directory;
|
|
}
|
|
|
|
/** Replaces two occurences of a substring in a string by a pair of strings if
|
|
* that substring occurs twice in the string. This method is not greedy! You'll
|
|
* have to run it in a loop if you want to replace all occurences of the substring.
|
|
* This method provides special treatment for headlines.
|
|
* @param input the string that something is to be replaced in
|
|
* @param pat substring to be replaced
|
|
* @param repl1 string substring gets replaced by on uneven occurences
|
|
* @param repl2 string substring gets replaced by on even occurences
|
|
*/
|
|
//[MN]
|
|
private String pairReplace(String input, final String pat, final String repl1, final String repl2){
|
|
String direlem = ""; //string to keep headlines until they get added to List dirElements
|
|
int p0 = 0;
|
|
int p1 = 0;
|
|
final int l = pat.length();
|
|
//replace pattern if a pair of the pattern can be found in the line
|
|
if( ((p0 = input.indexOf(pat)) >= 0) && ((p1 = input.indexOf(pat, p0 + l)) >= 0) ) {
|
|
//extra treatment for headlines
|
|
if((pat.equals("===="))||(pat.equals("==="))||(pat.equals("=="))){
|
|
//add anchor and create headline
|
|
direlem = input.substring(p0 + l, p1);
|
|
//counting double headlines
|
|
int doubles = 0;
|
|
for(int i=0;i<headlines;i++){
|
|
if(dirElements.get(i).substring(1).equals(direlem)){
|
|
doubles++;
|
|
}
|
|
}
|
|
String anchor = direlem.replaceAll(" ","_").replaceAll("[^a-zA-Z0-9_]",""); //replace blanks with underscores and delete everything thats not a regular character, a number or _
|
|
//if there are doubles, add underscore and number of doubles plus one
|
|
if(doubles>0){
|
|
anchor = anchor + "_" + (doubles+1);
|
|
}
|
|
input = input.substring(0, p0) + "<a name=\""+anchor+"\"></a>" + repl1 +
|
|
direlem + repl2 + input.substring(p1 + l);
|
|
//add headlines to list of headlines (so TOC can be created)
|
|
if(pat.equals("====")) dirElements.add("3"+direlem);
|
|
else if(pat.equals("===")) dirElements.add("2"+direlem);
|
|
else if(pat.equals("==")) dirElements.add("1"+direlem);
|
|
headlines++;
|
|
}
|
|
else{
|
|
input = input.substring(0, p0) + repl1 +
|
|
(/*direlem =*/ input.substring(p0 + l, p1)) + repl2 +
|
|
input.substring(p1 + l);
|
|
}
|
|
}
|
|
//recursion if a pair of the pattern can still be found in the line
|
|
if( ((p0 = input.indexOf(pat)) >= 0) && (input.indexOf(pat,p0 + l) >= 0) ){
|
|
input = pairReplace(input, pat, repl1, repl2);
|
|
}
|
|
return input;
|
|
}
|
|
|
|
/** Replaces wiki tags with HTML tags.
|
|
* @param result a line of text
|
|
* @param switchboard
|
|
* @return the line of text with HTML tags instead of wiki tags
|
|
*/
|
|
public String transformLine(String result, final String publicAddress, final plasmaSwitchboard switchboard) {
|
|
//If HTML has not bee replaced yet (can happen if method gets called in recursion), replace now!
|
|
if (!replacedHTML || preformattedSpan){
|
|
result = htmlFilterCharacterCoding.unicode2html(result, true);
|
|
replacedHTML = true;
|
|
}
|
|
|
|
//check if line contains escape symbols([= =]) or if we are in an escape sequence already.
|
|
if ((result.indexOf("[=")>=0)||(result.indexOf("=]")>=0)||(escapeSpan)){
|
|
result = escapeTag(result, publicAddress, switchboard);
|
|
}
|
|
|
|
//check if line contains preformatted symbols or if we are in a preformatted sequence already.
|
|
else if ((result.indexOf("<pre>")>=0)||(result.indexOf("</pre>")>=0)||(preformattedSpan)){
|
|
result = preformattedTag(result, publicAddress, switchboard);
|
|
}
|
|
|
|
//transform page as usual
|
|
else {
|
|
|
|
//tables first -> wiki-tags in cells can be treated after that
|
|
result = processTable(result, switchboard);
|
|
|
|
// format lines
|
|
if (result.startsWith(" ")) result = "<tt>" + result.substring(1) + "</tt>";
|
|
if (result.startsWith("----")) result = "<hr />";
|
|
|
|
// citings contributed by [MN]
|
|
if(result.startsWith(":")){
|
|
String head = "";
|
|
String tail = "";
|
|
while(result.startsWith(":")){
|
|
head = head + "<blockquote>";
|
|
tail = tail + "</blockquote>";
|
|
result = result.substring(1);
|
|
}
|
|
result = head + result + tail;
|
|
}
|
|
// end contrib [MN]
|
|
|
|
// format headers
|
|
result = pairReplace(result,"====","<h4>","</h4>");
|
|
result = pairReplace(result,"===","<h3>","</h3>");
|
|
result = pairReplace(result,"==","<h2>","</h2>");
|
|
|
|
result = pairReplace(result,"'''''","<b><i>","</i></b>");
|
|
result = pairReplace(result,"'''","<b>","</b>");
|
|
result = pairReplace(result,"''","<i>","</i>");
|
|
|
|
result = unorderedList(result);
|
|
result = orderedList(result);
|
|
result = definitionList(result);
|
|
|
|
result = linksAndImages(result, publicAddress, switchboard);
|
|
|
|
}
|
|
|
|
if (!preformatted) replacedHTML = false;
|
|
if ((result.endsWith("</li>"))||(defList)||(escape)||(preformatted)||(table)||(cellprocessing)) return result;
|
|
return result + "<br />";
|
|
}
|
|
}
|