📄 jspwikimarkupparser.java
字号:
/* JSPWiki - a JSP-based WikiWiki clone. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package com.ecyrd.jspwiki.parser;import java.io.IOException;import java.io.Reader;import java.io.StringReader;import java.text.MessageFormat;import java.util.*;import javax.xml.transform.Result;import org.apache.commons.lang.StringEscapeUtils;import org.apache.commons.lang.StringUtils;import org.apache.log4j.Logger;import org.apache.oro.text.GlobCompiler;import org.apache.oro.text.regex.*;import org.jdom.*;import com.ecyrd.jspwiki.*;import com.ecyrd.jspwiki.attachment.Attachment;import com.ecyrd.jspwiki.attachment.AttachmentManager;import com.ecyrd.jspwiki.auth.WikiSecurityException;import com.ecyrd.jspwiki.auth.acl.Acl;import com.ecyrd.jspwiki.i18n.InternationalizationManager;import com.ecyrd.jspwiki.plugin.PluginException;import com.ecyrd.jspwiki.plugin.PluginManager;import com.ecyrd.jspwiki.plugin.WikiPlugin;import com.ecyrd.jspwiki.providers.ProviderException;import com.ecyrd.jspwiki.render.CleanTextRenderer;import com.ecyrd.jspwiki.render.RenderingManager;/** * Parses JSPWiki-style markup into a WikiDocument DOM tree. This class is the * heart and soul of JSPWiki : make sure you test properly anything that is added, * or else it breaks down horribly. * * @since 2.4 */public class JSPWikiMarkupParser extends MarkupParser{ /** Name of the outlink image; relative path to the JSPWiki directory. */ private static final String OUTLINK_IMAGE = "images/out.png"; /** The value for anchor element <tt>class</tt> attributes when used * for wiki page (normal) links. The value is "wikipage". */ public static final String CLASS_WIKIPAGE = "wikipage"; /** The value for anchor element <tt>class</tt> attributes when used * for edit page links. The value is "createpage". */ public static final String CLASS_EDITPAGE = "createpage"; /** The value for anchor element <tt>class</tt> attributes when used * for interwiki page links. The value is "interwiki". */ public static final String CLASS_INTERWIKI = "interwiki"; protected static final int READ = 0; protected static final int EDIT = 1; protected static final int EMPTY = 2; // Empty message protected static final int LOCAL = 3; protected static final int LOCALREF = 4; protected static final int IMAGE = 5; protected static final int EXTERNAL = 6; protected static final int INTERWIKI = 7; protected static final int IMAGELINK = 8; protected static final int IMAGEWIKILINK = 9; protected static final int ATTACHMENT = 10; private static Logger log = Logger.getLogger( JSPWikiMarkupParser.class ); private boolean m_isbold = false; private boolean m_isitalic = false; private boolean m_istable = false; private boolean m_isPre = false; private boolean m_isEscaping = false; private boolean m_isdefinition = false; private boolean m_isPreBlock = false; /** Contains style information, in multiple forms. */ private Stack<Boolean> m_styleStack = new Stack<Boolean>(); // general list handling private int m_genlistlevel = 0; private StringBuilder m_genlistBulletBuffer = new StringBuilder(10); // stores the # and * pattern private boolean m_allowPHPWikiStyleLists = true; private boolean m_isOpenParagraph = false; /** Keeps image regexp Patterns */ private List<Pattern> m_inlineImagePatterns; /** Parser for extended link functionality. */ private LinkParser m_linkParser = new LinkParser(); private PatternMatcher m_inlineMatcher = new Perl5Matcher(); /** Keeps track of any plain text that gets put in the Text nodes */ private StringBuilder m_plainTextBuf = new StringBuilder(20); private Element m_currentElement; /** Keep track of duplicate header names. */ private Map<String, Integer> m_titleSectionCounter = new HashMap<String, Integer>(); /** * This property defines the inline image pattern. It's current value * is jspwiki.translatorReader.inlinePattern */ public static final String PROP_INLINEIMAGEPTRN = "jspwiki.translatorReader.inlinePattern"; /** If true, consider CamelCase hyperlinks as well. */ public static final String PROP_CAMELCASELINKS = "jspwiki.translatorReader.camelCaseLinks"; /** If true, all hyperlinks are translated as well, regardless whether they are surrounded by brackets. */ public static final String PROP_PLAINURIS = "jspwiki.translatorReader.plainUris"; /** If true, all outward links (external links) have a small link image appended. */ public static final String PROP_USEOUTLINKIMAGE = "jspwiki.translatorReader.useOutlinkImage"; /** If true, all outward attachment info links have a small link image appended. */ public static final String PROP_USEATTACHMENTIMAGE = "jspwiki.translatorReader.useAttachmentImage"; /** If set to "true", all external links are tagged with 'rel="nofollow"' */ public static final String PROP_USERELNOFOLLOW = "jspwiki.translatorReader.useRelNofollow"; /** If true, then considers CamelCase links as well. */ private boolean m_camelCaseLinks = false; /** If true, then generate special output for wysiwyg editing in certain cases */ private boolean m_wysiwygEditorMode = false; /** If true, consider URIs that have no brackets as well. */ // FIXME: Currently reserved, but not used. private boolean m_plainUris = false; /** If true, all outward links use a small link image. */ private boolean m_useOutlinkImage = true; private boolean m_useAttachmentImage = true; /** If true, allows raw HTML. */ private boolean m_allowHTML = false; private boolean m_useRelNofollow = false; private PatternCompiler m_compiler = new Perl5Compiler(); static final String WIKIWORD_REGEX = "(^|[[:^alnum:]]+)([[:upper:]]+[[:lower:]]+[[:upper:]]+[[:alnum:]]*|(http://|https://|mailto:)([A-Za-z0-9_/\\.\\+\\?\\#\\-\\@=&;~%]+))"; private PatternMatcher m_camelCaseMatcher = new Perl5Matcher(); private Pattern m_camelCasePattern; private int m_rowNum = 1; private Heading m_lastHeading = null; /** * The default inlining pattern. Currently "*.png" */ public static final String DEFAULT_INLINEPATTERN = "*.png"; /** * This list contains all IANA registered URI protocol * types as of September 2004 + a few well-known extra types. * * JSPWiki recognises all of them as external links. * * This array is sorted during class load, so you can just dump * here whatever you want in whatever order you want. */ static final String[] EXTERNAL_LINKS = { "http:", "ftp:", "https:", "mailto:", "news:", "file:", "rtsp:", "mms:", "ldap:", "gopher:", "nntp:", "telnet:", "wais:", "prospero:", "z39.50s", "z39.50r", "vemmi:", "imap:", "nfs:", "acap:", "tip:", "pop:", "dav:", "opaquelocktoken:", "sip:", "sips:", "tel:", "fax:", "modem:", "soap.beep:", "soap.beeps", "xmlrpc.beep", "xmlrpc.beeps", "urn:", "go:", "h323:", "ipp:", "tftp:", "mupdate:", "pres:", "im:", "mtqp", "smb:" }; private static final String INLINE_IMAGE_PATTERNS = "JSPWikiMarkupParser.inlineImagePatterns"; private static final String CAMELCASE_PATTERN = "JSPWikiMarkupParser.camelCasePattern"; private static final String[] CLASS_TYPES = { CLASS_WIKIPAGE, CLASS_EDITPAGE, "", "footnote", "footnoteref", "", "external", CLASS_INTERWIKI, "external", CLASS_WIKIPAGE, "attachment" }; /** * This Comparator is used to find an external link from c_externalLinks. It * checks if the link starts with the other arraythingie. */ private static Comparator<String> c_startingComparator = new StartingComparator(); static { Arrays.sort( EXTERNAL_LINKS ); } /** * Creates a markup parser. * * @param context The WikiContext which controls the parsing * @param in Where the data is read from. */ public JSPWikiMarkupParser( WikiContext context, Reader in ) { super( context, in ); initialize(); } /** * @param m_engine The WikiEngine this reader is attached to. Is * used to figure out of a page exits. */ // FIXME: parsers should be pooled for better performance. @SuppressWarnings("unchecked") private void initialize() { PatternCompiler compiler = new GlobCompiler(); List<Pattern> compiledpatterns; // // We cache compiled patterns in the engine, since their creation is // really expensive // compiledpatterns = (List<Pattern>)m_engine.getAttribute( INLINE_IMAGE_PATTERNS ); if( compiledpatterns == null ) { compiledpatterns = new ArrayList<Pattern>(20); Collection ptrns = getImagePatterns( m_engine ); // // Make them into Regexp Patterns. Unknown patterns // are ignored. // for( Iterator i = ptrns.iterator(); i.hasNext(); ) { try { compiledpatterns.add( compiler.compile( (String)i.next(), GlobCompiler.DEFAULT_MASK|GlobCompiler.READ_ONLY_MASK ) ); } catch( MalformedPatternException e ) { log.error("Malformed pattern in properties: ", e ); } } m_engine.setAttribute( INLINE_IMAGE_PATTERNS, compiledpatterns ); } m_inlineImagePatterns = Collections.unmodifiableList(compiledpatterns); m_camelCasePattern = (Pattern) m_engine.getAttribute( CAMELCASE_PATTERN ); if( m_camelCasePattern == null ) { try { m_camelCasePattern = m_compiler.compile( WIKIWORD_REGEX, Perl5Compiler.DEFAULT_MASK|Perl5Compiler.READ_ONLY_MASK ); } catch( MalformedPatternException e ) { log.fatal("Internal error: Someone put in a faulty pattern.",e); throw new InternalWikiException("Faulty camelcasepattern in TranslatorReader"); } m_engine.setAttribute( CAMELCASE_PATTERN, m_camelCasePattern ); } // // Set the properties. // Properties props = m_engine.getWikiProperties(); String cclinks = (String)m_context.getPage().getAttribute( PROP_CAMELCASELINKS ); if( cclinks != null ) { m_camelCaseLinks = TextUtil.isPositive( cclinks ); } else { m_camelCaseLinks = TextUtil.getBooleanProperty( props, PROP_CAMELCASELINKS, m_camelCaseLinks ); } Boolean wysiwygVariable = (Boolean)m_context.getVariable( RenderingManager.WYSIWYG_EDITOR_MODE ); if( wysiwygVariable != null ) { m_wysiwygEditorMode = wysiwygVariable.booleanValue(); } m_plainUris = getLocalBooleanProperty( m_context, props, PROP_PLAINURIS, m_plainUris ); m_useOutlinkImage = getLocalBooleanProperty( m_context, props, PROP_USEOUTLINKIMAGE, m_useOutlinkImage ); m_useAttachmentImage = getLocalBooleanProperty( m_context, props, PROP_USEATTACHMENTIMAGE, m_useAttachmentImage ); m_allowHTML = getLocalBooleanProperty( m_context, props, MarkupParser.PROP_ALLOWHTML, m_allowHTML ); m_useRelNofollow = getLocalBooleanProperty( m_context, props, PROP_USERELNOFOLLOW, m_useRelNofollow ); if( m_engine.getUserManager().getUserDatabase() == null || m_engine.getAuthorizationManager() == null ) { disableAccessRules(); } m_context.getPage().setHasMetadata(); } /** * This is just a simple helper method which will first check the context * if there is already an override in place, and if there is not, * it will then check the given properties. * * @param context WikiContext to check first * @param props Properties to check next * @param key What key are we searching for? * @param defValue Default value for the boolean * @return True or false */ private static boolean getLocalBooleanProperty( WikiContext context, Properties props, String key, boolean defValue ) { Object bool = context.getVariable(key); if( bool != null ) { return TextUtil.isPositive( (String) bool ); } return TextUtil.getBooleanProperty( props, key, defValue ); } /** * Figure out which image suffixes should be inlined. * @return Collection of Strings with patterns. * * @param engine The WikiEngine from which the patterns are read. */ // FIXME: Does not belong here; should be elsewhere public static Collection getImagePatterns( WikiEngine engine ) { Properties props = engine.getWikiProperties(); ArrayList<String> ptrnlist = new ArrayList<String>(); for( Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { String name = (String) e.nextElement(); if( name.startsWith( PROP_INLINEIMAGEPTRN ) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -