Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package info.bliki.wiki.filter;
import info.bliki.wiki.model.Configuration;
import info.bliki.wiki.model.IWikiModel;
import info.bliki.wiki.tags.util.WikiTagNode;
import info.bliki.wiki.template.ITemplateFunction;
import info.bliki.wiki.template.Safesubst;
import info.bliki.wiki.template.Subst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static info.bliki.wiki.filter.AbstractWikipediaParser.getRedirectedTemplateContent;
import static info.bliki.wiki.filter.WikipediaParser.parseRedirect;
/**
* A template parser for the first pass in the parsing of a Wikipedia text
*
* @see WikipediaParser for the second pass
*/
public class TemplateParser extends AbstractParser {
public static final String TEMPLATE_PARSER_ERROR = "TemplateParserError";
private static final Pattern HTML_COMMENT_PATTERN = Pattern.compile("");
private static final String SUBST = "subst:";
private static final String SAFESUBST = "safesubst:";
private static final int SUBST_LENGTH = SUBST.length();
private static final int SAFESUBST_LENGTH = SAFESUBST.length();
protected static Logger logger = LoggerFactory.getLogger(TemplateParser.class);
private final boolean fParseOnlySignature;
private final boolean fRenderTemplate;
private boolean fOnlyIncludeFlag;
public TemplateParser(String stringSource) {
this(stringSource, false, false);
}
public TemplateParser(String stringSource, boolean parseOnlySignature, boolean renderTemplate) {
this(stringSource, parseOnlySignature, renderTemplate, false);
}
public TemplateParser(String stringSource, boolean parseOnlySignature, boolean renderTemplate, boolean onlyIncludeFlag) {
super(stringSource);
fParseOnlySignature = parseOnlySignature;
fRenderTemplate = renderTemplate;
fOnlyIncludeFlag = onlyIncludeFlag;
}
public static void parse(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean renderTemplate) throws IOException {
parse(rawWikitext, wikiModel, writer, false, renderTemplate);
}
/**
* Parse the wiki texts templates, comments and signatures into the given
* StringBuilder.
*
* @param rawWikitext
* @param wikiModel
* @param writer
* @param parseOnlySignature
* change only the signature string and ignore templates and comments
* parsing
* @param renderTemplate
*/
public static void parse(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean parseOnlySignature,
boolean renderTemplate) throws IOException {
parseRecursive(rawWikitext, wikiModel, writer, parseOnlySignature, renderTemplate);
}
protected static void parseRecursive(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean parseOnlySignature,
boolean renderTemplate) throws IOException {
parseRecursive(rawWikitext, wikiModel, writer, parseOnlySignature, renderTemplate, null);
}
/**
* Preprocess parsing of the <includeonly>,
* <onlyinclude> and <noinclude> tags
*
* @param writer writer for output
* @param diff
* @return true if an onlyinclude section was parsed
* @throws IOException
*/
private boolean parsePreprocessRecursive(StringBuilder writer, int diff) throws IOException {
StringBuilder buf = new StringBuilder(fCurrentPosition - fWhiteStartPosition);
appendContent(buf, fWhiteStart, fWhiteStartPosition, diff, true);
int startIndex = Util.indexOfTemplateParsing(buf);
if (startIndex < 0) {
writer.append(buf);
return false;
} else {
return parsePreprocessRecursive(startIndex, buf.toString(), fWikiModel, writer, fRenderTemplate, false, null);
}
}
/**
* Preprocess parsing of the
* <includeonly>,
* <onlyinclude> and <noinclude> tags.
* Also performs template parameter substitution.
*/
public static boolean parsePreprocessRecursive(int startIndex, String rawWikitext,
IWikiModel wikiModel,
StringBuilder writer,
boolean renderTemplate,
boolean onlyIncludeFlag,
Map templateParameterMap) throws IOException {
try {
int templateLevel = wikiModel.incrementTemplateRecursionLevel();
if (templateLevel > Configuration.TEMPLATE_RECURSION_LIMIT) {
writer.append("Error - template recursion limit exceeded parsing templates.");
return false;
}
StringBuilder sb = new StringBuilder(rawWikitext.length());
TemplateParser parser = new TemplateParser(rawWikitext, false, renderTemplate, onlyIncludeFlag);
parser.setModel(wikiModel);
parser.runPreprocessParser(0, startIndex, sb, /* ignoreTemplateTags */ false);
writer.append(substituteParameters(templateParameterMap, wikiModel, sb));
return parser.fOnlyIncludeFlag;
} catch (Exception | Error e) {
handleParserError(e, writer);
return false;
} finally {
wikiModel.decrementTemplateRecursionLevel();
}
}
private static StringBuilder substituteParameters(Map templateParameterMap, IWikiModel wikiModel, StringBuilder writer) {
final boolean hasParamsToReplace = templateParameterMap != null && !templateParameterMap.isEmpty();
final boolean hasEmptyDefaultParams = writer.indexOf("{{{|") != -1;
if (hasParamsToReplace || hasEmptyDefaultParams) {
TemplateParser scanner = new TemplateParser(writer.toString());
scanner.setModel(wikiModel);
StringBuilder result = scanner.replaceTemplateParameters(templateParameterMap, 0);
if (result != null) {
return result;
}
}
return writer;
}
public static void parseRecursive(String rawWikitext, IWikiModel wikiModel, Appendable writer,
boolean parseOnlySignature,
boolean renderTemplate, Map templateParameterMap) throws IOException {
int startIndex = Util.indexOfTemplateParsing(rawWikitext);
if (startIndex < 0) {
writer.append(rawWikitext);
return;
}
StringBuilder sb = new StringBuilder(rawWikitext.length());
parsePreprocessRecursive(startIndex, rawWikitext, wikiModel, sb, renderTemplate, false, templateParameterMap);
if (parseOnlySignature) {
writer.append(sb);
return;
}
try {
int templateLevel = wikiModel.incrementTemplateRecursionLevel();
if (templateLevel > Configuration.TEMPLATE_RECURSION_LIMIT) {
writer.append("Error - template recursion limit exceeded parsing templates.");
return;
}
TemplateParser parser = new TemplateParser(sb.toString(), false, renderTemplate);
parser.setModel(wikiModel);
sb = new StringBuilder(sb.length());
// process and a parameter/value map.
*
Substitute the raw template text into the existing text and replace all
* template parameters with their value in
* TemplateParser.parseRecursive()
*
*
* @param writer
* @param startTemplatePosition
* @param templateEndPosition
* @return
* @throws IOException
*/
private boolean parseTemplate(Appendable writer, int startTemplatePosition, int templateEndPosition) throws IOException {
fCurrentPosition = templateEndPosition;
int endPosition = fCurrentPosition;
String plainContent;
int endOffset = fCurrentPosition - 2;
Object[] objs = createParameterMap(fSource, startTemplatePosition, fCurrentPosition - startTemplatePosition - 2);
@SuppressWarnings("unchecked")
List parts = (List) objs[0];
String templateName = ((String) objs[1]);
StringBuilder buf = new StringBuilder((templateName.length()) + (templateName.length() / 10));
TemplateParser.parse(templateName, fWikiModel, buf, false);
templateName = buf.toString();
int currOffset = TemplateParser.checkParserFunction(buf);
if (currOffset > 0) {
String function = templateName.substring(0, currOffset - 1).trim();
if (Configuration.PARSER_FUNCTIONS) {
System.out.println(function);
}
ITemplateFunction templateFunction = fWikiModel.getTemplateFunction(function);
if (templateFunction != null) {
// if (function.charAt(0) == '#') {
// #if:, #ifeq:,...
parts.set(0, templateName.substring(currOffset));
// if (Configuration.PARSER_FUNCTIONS) {
// System.out.println(function + ": " + parts);
// }
plainContent = templateFunction.parseFunction(parts, fWikiModel, fSource, startTemplatePosition + currOffset, endOffset,
false);
fCurrentPosition = endPosition;
if (plainContent != null) {
TemplateParser.parseRecursive(plainContent, fWikiModel, writer, false, false);
}
return true;
}
fCurrentPosition = endOffset + 2;
}
if (Util.isInvalidTemplateName(templateName)) {
return false;
}
fCurrentPosition = endPosition;
LinkedHashMap parameterMap = new LinkedHashMap<>();
if (parts.size() > 1) {
List unnamedParameters = new ArrayList<>();
for (int i = 1; i < parts.size(); i++) {
createSingleParameter(parts.get(i), fWikiModel, parameterMap, unnamedParameters);
}
mergeParameters(parameterMap, unnamedParameters);
}
fWikiModel.substituteTemplateCall(templateName, parameterMap, writer);
return true;
}
/**
* If template calls have a mix between named and unnamed parameters, the
* collected unnamedParameters are merged into the
* parameterMap.
*
*
* See Help:Template#Mix_of_named_and_unnamed_parameters
*/
public static void mergeParameters(LinkedHashMap parameterMap, List unnamedParameters) {
if (unnamedParameters.size() == 0) {
return;
}
int unnamedParameterIndex = 1;
for (String param : unnamedParameters) {
String key = Integer.toString(unnamedParameterIndex++);
if (!parameterMap.containsKey(key))
parameterMap.put(key, param);
}
}
/**
* Parse a single template parameter {{{...}}}
* @throws IOException
*/
private void parseTemplateParameter(Appendable writer, int startTemplatePosition, int templateEndPosition) throws IOException {
String plainContent = fStringSource.substring(startTemplatePosition - 2, templateEndPosition);
fCurrentPosition = templateEndPosition;
int indx = plainContent.indexOf("{{{");
if (indx >= 0) {
TemplateParser scanner = new TemplateParser(plainContent);
scanner.setModel(fWikiModel);
StringBuilder plainBuffer = scanner.replaceTemplateParameters(null, 0);
if (plainBuffer == null) {
writer.append(plainContent);
return;
}
TemplateParser.parseRecursive(plainBuffer.toString().trim(), fWikiModel, writer, false, false);
}
}
/**
* Create a map from the parameters defined in a template call
*
* @return the templates parameters java.util.List at index [0]
* and the template name at index [1]
*
*/
public static Object[] createParameterMap(char[] src, int startOffset, int len) {
Object[] objs = new Object[2];
int currOffset = startOffset;
int endOffset = startOffset + len;
List resultList = new ArrayList<>();
objs[0] = resultList;
splitByPipe(src, currOffset, endOffset, resultList);
if (resultList.size() <= 1) {
// set the template name
objs[1] = new String(src, startOffset, len).trim();
} else {
objs[1] = resultList.get(0).trim();
}
return objs;
}
/**
* Create a single parameter, defined in a template call, and add it to the
* named parameters map or unnamed parameter list
*
*
* See Help:Template:
* Remember that whitespace characters (spaces, tabs, carriage returns and
* line feeds) are not automatically stripped from the start and end of
* unnamed parameters (as they are from named parameters). Including such
* characters (or any other non-visible characters in any parameters) may in
* some cases affect the template's behaviour in unexpected ways. (Template
* designers can use {{StripWhitespace}} to remove unwanted whitespace in
* unnamed parameters.)
*
*
* @param srcString
* @param namedParameterMap
* a key/value pairs for name and value of a template parameter
* @param unnamedParams
* a list of unnamed parameter values
*/
public static void createSingleParameter(String srcString, IWikiModel wikiModel, Map namedParameterMap,
List unnamedParams) {
int currOffset = 0;
char[] src = srcString.toCharArray();
int endOffset = srcString.length();
char ch;
String parameter = null;
String value;
boolean equalCharParsed = false;
int lastOffset = currOffset;
int[] temp = new int[] { -1, -1 };
try {
while (currOffset < endOffset) {
ch = src[currOffset++];
if (ch == '[' && src[currOffset] == '[') {
currOffset++;
temp[0] = findNestedEnd(src, '[', ']', currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
}
} else if (ch == '{' && src[currOffset] == '{') {
currOffset++;
if (src[currOffset] == '{' && src[currOffset + 1] != '{') {
currOffset++;
temp = findNestedParamEnd(src, currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
} else {
if (temp[1] >= 0) {
currOffset = temp[1];
}
}
} else {
temp[0] = findNestedTemplateEnd(src, currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
}
}
} else if (ch == '=') {
if (!equalCharParsed) {
parameter = srcString.substring(lastOffset, currOffset - 1).trim();
lastOffset = currOffset;
}
equalCharParsed = true;
}
}
} catch (IndexOutOfBoundsException e) {
} finally {
if (currOffset >= lastOffset) {
try {
value = srcString.substring(lastOffset, currOffset);
boolean parameterParsingMode = wikiModel.isParameterParsingMode();
try {
wikiModel.setParameterParsingMode(true);
if (parameter != null) {
StringBuilder buf = new StringBuilder(value.length());
TemplateParser.parseRecursive(value, wikiModel, buf, false, false);
value = Util.trimNewlineRight(buf.toString());
namedParameterMap.put(parameter, value);
} else {
// whitespace characters are not automatically stripped from the
// start and end of unnamed parameters!
StringBuilder buf = new StringBuilder(value.length());
TemplateParser.parseRecursive(value, wikiModel, buf, false, false);
unnamedParams.add(buf.toString());
}
} finally {
wikiModel.setParameterParsingMode(parameterParsingMode);
}
} catch (IOException ignored) {
}
}
}
}
/**
* Check if this template contains a template function
*
* Note: repositions this#fCurrentPosition behind the parser function string
* if possible
*
* @param plainContent
* @return the offset behind the ´:´ character at the end of the
* parser function name or -1 if no parser function can
* be found in this template.
*/
public static int checkParserFunction(CharSequence plainContent) {
int currOffset = 0;
int len = plainContent.length();
char ch;
while (currOffset < len) {
ch = plainContent.charAt(currOffset++);
if (Character.isLetter(ch) || ch == '#' || ch == '$') {
while (currOffset < len) {
ch = plainContent.charAt(currOffset++);
if (ch == ':') {
return currOffset;
} else if (!Character.isLetterOrDigit(ch) && ch != '$') {
return -1;
}
}
break;
} else if (!Character.isWhitespace(ch)) {
return -1;
}
}
return -1;
}
protected boolean parseHTMLCommentTags(Appendable writer) throws IOException {
if (fStringSource.startsWith("");
// end of HTML comment
if (temp >= 0) {
temp = readWhitespaceUntilEndOfLine(0);
if (temp >= 0) {
fCurrentPosition++;
}
}
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
return false;
}
/**
* Replace the wiki template parameters in the given template string
*
* @param templateParameters
* @param curlyBraceOffset
* TODO
* @param template
*
* @return null if no replacement could be found
*/
@Nullable public StringBuilder replaceTemplateParameters(@Nullable Map templateParameters, int curlyBraceOffset) {
StringBuilder buffer = null;
int bufferStart = 0;
try {
int level = fWikiModel.incrementRecursionLevel();
if (level > Configuration.PARSER_RECURSION_LIMIT) {
return null; // no further processing
}
fScannerPosition += curlyBraceOffset;
char ch;
int parameterStart = -1;
StringBuilder recursiveResult;
boolean isDefaultValue;
while (true) {
ch = fSource[fScannerPosition++];
if (ch == '{' && fSource[fScannerPosition] == '{' && fSource[fScannerPosition + 1] == '{'
&& fSource[fScannerPosition + 2] != '{') {
fScannerPosition += 2;
parameterStart = fScannerPosition;
int temp[] = findNestedParamEnd(fSource, parameterStart);
if (temp[0] >= 0) {
fScannerPosition = temp[0];
List list = splitByPipe(fSource, parameterStart, fScannerPosition - 3, null);
if (list.size() > 0) {
String parameterString = list.get(0).trim();
TemplateParser scanner1 = new TemplateParser(parameterString);
scanner1.setModel(fWikiModel);
recursiveResult = scanner1.replaceTemplateParameters(templateParameters, curlyBraceOffset);
if (recursiveResult != null) {
parameterString = recursiveResult.toString();
}
String value = null;
isDefaultValue = false;
if (templateParameters != null) {
value = templateParameters.get(parameterString);
}
if (value == null && list.size() > 1) {
// default value is available for the template
value = list.get(1);
isDefaultValue = true;
}
if (value != null) {
if (value.length() <= Configuration.TEMPLATE_VALUE_LIMIT) {
if (buffer == null) {
buffer = new StringBuilder(fSource.length + 128);
}
if (bufferStart < fScannerPosition) {
buffer.append(fSource, bufferStart, parameterStart - bufferStart - 3);
}
TemplateParser scanner2 = new TemplateParser(value);
scanner2.setModel(fWikiModel);
if (isDefaultValue) {
recursiveResult = scanner2.replaceTemplateParameters(templateParameters, curlyBraceOffset);
} else {
recursiveResult = scanner2.replaceTemplateParameters(null, curlyBraceOffset);
}
if (recursiveResult != null) {
buffer.append(recursiveResult);
} else {
buffer.append(value);
}
bufferStart = fScannerPosition;
}
}
}
fScannerPosition = temp[0];
parameterStart = -1;
}
}
if (buffer != null && buffer.length() > Configuration.TEMPLATE_BUFFER_LIMIT) {
// Controls the scanner, when infinite recursion occurs the
// buffer grows out of control.
return buffer;
}
}
} catch (IndexOutOfBoundsException e) {
// ignore
} finally {
fWikiModel.decrementRecursionLevel();
}
if (buffer != null && bufferStart < fScannerPosition) {
buffer.append(fSource, bufferStart, fScannerPosition - bufferStart - 1);
}
return buffer;
}
}