You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/08/03 14:12:49 UTC
svn commit: r682139 [2/6] - in
/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki:
./ action/
Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/TranslatorReader.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/TranslatorReader.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/TranslatorReader.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/TranslatorReader.java Sun Aug 3 05:12:47 2008
@@ -1,44 +1,35 @@
-/*
+/*
JSPWiki - a JSP-based WikiWiki clone.
- Copyright (C) 2001-2005 Janne Jalkanen (Janne.Jalkanen@iki.fi)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser 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
+ 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;
-import java.io.*;
-import java.text.MessageFormat;
-import java.util.*;
-
-import org.apache.log4j.Logger;
-import org.apache.oro.text.*;
-import org.apache.oro.text.regex.*;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Collection;
-import com.ecyrd.jspwiki.i18n.InternationalizationManager;
-import com.ecyrd.jspwiki.parser.Heading;
import com.ecyrd.jspwiki.parser.HeadingListener;
-import com.ecyrd.jspwiki.plugin.PluginManager;
-import com.ecyrd.jspwiki.plugin.PluginException;
-import com.ecyrd.jspwiki.plugin.WikiPlugin;
-import com.ecyrd.jspwiki.action.*;
-import com.ecyrd.jspwiki.attachment.AttachmentManager;
-import com.ecyrd.jspwiki.attachment.Attachment;
-import com.ecyrd.jspwiki.providers.ProviderException;
-import com.ecyrd.jspwiki.auth.acl.Acl;
-import com.ecyrd.jspwiki.auth.WikiSecurityException;
+import com.ecyrd.jspwiki.parser.JSPWikiMarkupParser;
+import com.ecyrd.jspwiki.parser.MarkupParser;
+import com.ecyrd.jspwiki.render.WikiRenderer;
+import com.ecyrd.jspwiki.render.XHTMLRenderer;
/**
* Handles conversion from Wiki format into fully featured HTML.
@@ -50,79 +41,11 @@
* <p>
* This class is officially deprecated in 2.3, and will be replaced
* with a dummy class later on. Please see MarkupParser.
- * @author Janne Jalkanen
* @deprecated
*/
-//FIXME2.6: Make use JSPWikiMarkupParser
//FIXME3.0: Remove
public class TranslatorReader extends Reader
{
- public static final int READ = 0;
- public static final int EDIT = 1;
- private static final int EMPTY = 2; // Empty message
- private static final int LOCAL = 3;
- private static final int LOCALREF = 4;
- private static final int IMAGE = 5;
- private static final int EXTERNAL = 6;
- private static final int INTERWIKI = 7;
- private static final int IMAGELINK = 8;
- private static final int IMAGEWIKILINK = 9;
- public static final int ATTACHMENT = 10;
- // private static final int ATTACHMENTIMAGE = 11;
-
- /** Lists all punctuation characters allowed in WikiMarkup. These
- will not be cleaned away. */
-
- private static final String PUNCTUATION_CHARS_ALLOWED = "._";
-
- /** Allow this many characters to be pushed back in the stream. In effect,
- this limits the size of a single heading line. */
- private static final int PUSHBACK_BUFFER_SIZE = 10*1024;
- private PushbackReader m_in;
-
- private StringReader m_data = new StringReader("");
-
- private static Logger log = Logger.getLogger( TranslatorReader.class );
-
- //private boolean m_iscode = false;
- private boolean m_isbold = false;
- private boolean m_isitalic = false;
- private boolean m_isTypedText = false;
- private boolean m_istable = false;
- private boolean m_isPre = false;
- private boolean m_isEscaping = false;
- private boolean m_isdefinition = false;
-
- /** Contains style information, in multiple forms. */
- private Stack<Boolean> m_styleStack = new Stack<Boolean>();
-
- // general list handling
- private int m_genlistlevel = 0;
- private StringBuffer m_genlistBulletBuffer = new StringBuffer(); // stores the # and * pattern
- private boolean m_allowPHPWikiStyleLists = true;
-
-
- private boolean m_isOpenParagraph = false;
-
- /** Tag that gets closed at EOL. */
- private String m_closeTag = null;
-
- private WikiEngine m_engine;
- private WikiContext m_context;
-
- /** Optionally stores internal wikilinks */
- private ArrayList<StringTransmutator> m_localLinkMutatorChain = new ArrayList<StringTransmutator>();
- private ArrayList<StringTransmutator> m_externalLinkMutatorChain = new ArrayList<StringTransmutator>();
- private ArrayList<StringTransmutator> m_attachmentLinkMutatorChain = new ArrayList<StringTransmutator>();
- private ArrayList<HeadingListener> m_headingListenerChain = new ArrayList<HeadingListener>();
-
- /** Keeps image regexp Patterns */
- private ArrayList m_inlineImagePatterns;
-
- private PatternMatcher m_inlineMatcher = new Perl5Matcher();
-
- private ArrayList<StringTransmutator> m_linkMutators = new ArrayList<StringTransmutator>();
-
/**
* This property defines the inline image pattern. It's current value
* is jspwiki.translatorReader.inlinePattern
@@ -149,78 +72,33 @@
/** If set to "true", enables plugins during parsing */
public static final String PROP_RUNPLUGINS = "jspwiki.translatorReader.runPlugins";
-
- /** If true, then considers CamelCase links as well. */
- private boolean m_camelCaseLinks = 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;
-
- /** If true, allows raw HTML. */
- private boolean m_allowHTML = false;
-
- /** If true, executes plugins; otherwise ignores them. */
- private boolean m_enablePlugins = true;
-
- private boolean m_useRelNofollow = false;
-
- private boolean m_inlineImages = true;
-
- private PatternMatcher m_matcher = new Perl5Matcher();
- private PatternCompiler m_compiler = new Perl5Compiler();
- private Pattern m_camelCasePtrn;
-
- private TextRenderer m_renderer;
-
/**
* The default inlining pattern. Currently "*.png"
*/
public static final String DEFAULT_INLINEPATTERN = "*.png";
- /**
- * These characters constitute word separators when trying
- * to find CamelCase links.
- */
- private static final String WORD_SEPARATORS = ",.|;+=&()";
-
- protected static final int BOLD = 0;
- protected static final int ITALIC = 1;
- protected static final int TYPED = 2;
-
- /**
- * 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.
- */
- static final String[] c_externalLinks = {
- "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 JSPWikiMarkupParser m_parser;
+ private WikiContext m_context;
+
/**
* Creates a TranslatorReader using the default HTML renderer.
+ * @param context WikiContext
+ * @param in The reader from which to read.
*/
public TranslatorReader( WikiContext context, Reader in )
{
- initialize( context, in, new HTMLRenderer() );
+ initialize( context, in );
}
- public TranslatorReader( WikiContext context, Reader in, TextRenderer renderer )
+ /**
+ * Creates a TranslatorReader.
+ * @param context WikiContext
+ * @param in Reader
+ * @param renderer Unused.
+ */
+ public TranslatorReader( WikiContext context, Reader in, Object renderer )
{
- initialize( context, in, renderer );
+ initialize( context, in );
}
/**
@@ -230,15 +108,7 @@
*/
public Reader setInputReader( Reader in )
{
- Reader old = m_in;
-
- if( in != null )
- {
- m_in = new PushbackReader( new BufferedReader( in ),
- PUSHBACK_BUFFER_SIZE );
- }
-
- return old;
+ return m_parser.setInputReader( in );
}
/**
@@ -248,101 +118,19 @@
// FIXME: TranslatorReaders should be pooled for better performance.
private void initialize( WikiContext context,
- Reader in,
- TextRenderer renderer )
+ Reader in )
{
- PatternCompiler compiler = new GlobCompiler();
- ArrayList compiledpatterns = new ArrayList();
-
- m_engine = context.getEngine();
m_context = context;
-
- m_renderer = renderer;
-
- setInputReader( in );
-
- 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() ) );
- }
- catch( MalformedPatternException e )
- {
- log.error("Malformed pattern in properties: ", e );
- }
- }
-
- m_inlineImagePatterns = compiledpatterns;
-
- try
- {
- m_camelCasePtrn = m_compiler.compile( "^([[:^alnum:]]*)([[:upper:]]+[[:lower:]]+[[:upper:]]+[[:alnum:]]*)[[:^alnum:]]*$" );
- }
- catch( MalformedPatternException e )
- {
- log.fatal("Internal error: Someone put in a faulty pattern.",e);
- throw new InternalWikiException("Faulty camelcasepattern in TranslatorReader");
- }
-
- //
- // 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 );
- }
-
- m_plainUris = TextUtil.getBooleanProperty( props,
- PROP_PLAINURIS,
- m_plainUris );
- m_useOutlinkImage = TextUtil.getBooleanProperty( props,
- PROP_USEOUTLINKIMAGE,
- m_useOutlinkImage );
- m_allowHTML = TextUtil.getBooleanProperty( props,
- PROP_ALLOWHTML,
- m_allowHTML );
-
- m_useRelNofollow = TextUtil.getBooleanProperty( props,
- PROP_USERELNOFOLLOW,
- m_useRelNofollow );
-
- String runplugins = m_engine.getVariable( m_context, PROP_RUNPLUGINS );
- if( runplugins != null ) enablePlugins( TextUtil.isPositive(runplugins));
-
- if( m_engine.getUserManager().getUserDatabase() == null || m_engine.getAuthorizationManager() == null )
- {
- disableAccessRules();
- }
-
- m_context.getPage().setHasMetadata();
+ m_parser = new JSPWikiMarkupParser( context, in );
}
/**
- * Sets the currently used renderer. This method is protected because
- * we only want to use it internally for now. The renderer interface
- * is not yet set to stone, so it's not expected that third parties
- * would use this.
+ * Does not work, don't try to use it.
+ * @param renderer Renderer.
*/
- protected void setRenderer( TextRenderer renderer )
+ protected void setRenderer( Object renderer )
{
- m_renderer = renderer;
+ throw new InternalWikiException("No longer functional - please use JSPWikiMarkupParser");
}
/**
@@ -355,10 +143,7 @@
*/
public void addLinkTransmutator( StringTransmutator mutator )
{
- if( mutator != null )
- {
- m_linkMutators.add( mutator );
- }
+ m_parser.addLinkTransmutator( mutator );
}
/**
@@ -369,10 +154,7 @@
*/
public void addLocalLinkHook( StringTransmutator mutator )
{
- if( mutator != null )
- {
- m_localLinkMutatorChain.add( mutator );
- }
+ m_parser.addLocalLinkHook( mutator );
}
/**
@@ -383,10 +165,7 @@
*/
public void addExternalLinkHook( StringTransmutator mutator )
{
- if( mutator != null )
- {
- m_externalLinkMutatorChain.add( mutator );
- }
+ m_parser.addExternalLinkHook( mutator );
}
/**
@@ -396,33 +175,30 @@
*/
public void addAttachmentLinkHook( StringTransmutator mutator )
{
- if( mutator != null )
- {
- m_attachmentLinkMutatorChain.add( mutator );
- }
+ m_parser.addAttachmentLinkHook( mutator );
}
+ /** Adds a listener to headings.
+ * @param listener Listener to add.
+ */
public void addHeadingListener( HeadingListener listener )
{
- if( listener != null )
- {
- m_headingListenerChain.add( listener );
- }
+ m_parser.addHeadingListener( listener );
}
- private boolean m_parseAccessRules = true;
-
+ /** Disables access rules parsing. */
public void disableAccessRules()
{
- m_parseAccessRules = false;
+ m_parser.disableAccessRules();
}
/**
* Can be used to turn on plugin execution on a translator-reader basis
+ * @param toggle on or off
*/
public void enablePlugins( boolean toggle )
{
- m_enablePlugins = toggle;
+ throw new InternalWikiException("No longer supported.");
}
/**
@@ -434,95 +210,20 @@
*/
public void enableImageInlining( boolean toggle )
{
- m_inlineImages = toggle;
+ m_parser.enableImageInlining( toggle );
}
/**
* Figure out which image suffixes should be inlined.
* @return Collection of Strings with patterns.
+ * @param engine WikiEngine
*/
protected 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 ) )
- {
- String ptrn = props.getProperty( name );
-
- ptrnlist.add( ptrn );
- }
- }
-
- if( ptrnlist.size() == 0 )
- {
- ptrnlist.add( DEFAULT_INLINEPATTERN );
- }
-
- return ptrnlist;
- }
-
- /**
- * Returns link name, if it exists; otherwise it returns null.
- */
- private String linkExists( String page )
- {
- try
- {
- if( page == null || page.length() == 0 ) return null;
-
- return m_engine.getFinalPageName( page );
- }
- catch( ProviderException e )
- {
- log.warn("TranslatorReader got a faulty page name!",e);
-
- return page; // FIXME: What would be the correct way to go back?
- }
- }
-
- /**
- * Calls a transmutator chain.
- *
- * @param list Chain to call
- * @param text Text that should be passed to the mutate() method
- * of each of the mutators in the chain.
- * @return The result of the mutation.
- */
-
- private String callMutatorChain( Collection list, String text )
- {
- if( list == null || list.size() == 0 )
- {
- return text;
- }
-
- for( Iterator i = list.iterator(); i.hasNext(); )
- {
- StringTransmutator m = (StringTransmutator) i.next();
-
- text = m.mutate( m_context, text );
- }
-
- return text;
+ throw new InternalWikiException("No longer supported - please use JSPWikiMarkupParser");
}
- private void callHeadingListenerChain( Heading param )
- {
- List list = m_headingListenerChain;
-
- for( Iterator i = list.iterator(); i.hasNext(); )
- {
- HeadingListener h = (HeadingListener) i.next();
-
- h.headingAdded( m_context, param );
- }
- }
/**
* Write a HTMLized link depending on its type.
@@ -531,29 +232,21 @@
* @param type Type of the link.
* @param link The actual link.
* @param text The user-visible text for the link.
+ * @return link
*/
public String makeLink( int type, String link, String text )
- {
+ {
+ return null;
+ /*
if( text == null ) text = link;
text = callMutatorChain( m_linkMutators, text );
return m_renderer.makeLink( type, link, text );
+ */
}
- /**
- * Just like makeLink, but also adds the section reference (#sect...)
- */
- private String makeLink( int type, String link, String text, String sectref )
- {
- if( text == null ) text = link;
-
- text = callMutatorChain( m_linkMutators, text );
-
- return m_renderer.makeLink( type, link, text, sectref );
- }
-
-
+
/**
* Cleans a Wiki name.
* <P>
@@ -566,2587 +259,44 @@
*/
public static String cleanLink( String link )
{
- StringBuffer clean = new StringBuffer();
-
- if( link == null ) return null;
-
- //
- // Compress away all whitespace and capitalize
- // all words in between.
- //
-
- StringTokenizer st = new StringTokenizer( link, " -" );
-
- while( st.hasMoreTokens() )
- {
- StringBuffer component = new StringBuffer(st.nextToken());
-
- component.setCharAt(0, Character.toUpperCase( component.charAt(0) ) );
-
- //
- // We must do this, because otherwise compiling on JDK 1.4 causes
- // a downwards incompatibility to JDK 1.3.
- //
- clean.append( component.toString() );
- }
-
- //
- // Remove non-alphanumeric characters that should not
- // be put inside WikiNames. Note that all valid
- // Unicode letters are considered okay for WikiNames.
- // It is the problem of the WikiPageProvider to take
- // care of actually storing that information.
- //
-
- for( int i = 0; i < clean.length(); i++ )
- {
- char ch = clean.charAt(i);
-
- if( !(Character.isLetterOrDigit(ch) ||
- PUNCTUATION_CHARS_ALLOWED.indexOf(ch) != -1 ))
- {
- clean.deleteCharAt(i);
- --i; // We just shortened this buffer.
- }
- }
-
- return clean.toString();
- }
-
- /**
- * Figures out if a link is an off-site link. This recognizes
- * the most common protocols by checking how it starts.
- */
-
- // FIXME: Should really put the external link types to a sorted set,
- // then searching for them would be faster.
- private boolean isExternalLink( String link )
- {
- for( int i = 0; i < c_externalLinks.length; i++ )
- {
- if( link.startsWith( c_externalLinks[i] ) ) return true;
- }
-
- return false;
- }
-
- /**
- * Returns true, if the link in question is an access
- * rule.
- */
- private static boolean isAccessRule( String link )
- {
- return link.startsWith("{ALLOW") || link.startsWith("{DENY");
- }
-
- /**
- * Matches the given link to the list of image name patterns
- * to determine whether it should be treated as an inline image
- * or not.
- */
- private boolean isImageLink( String link )
- {
- if( m_inlineImages )
- {
- for( Iterator i = m_inlineImagePatterns.iterator(); i.hasNext(); )
- {
- if( m_inlineMatcher.matches( link, (Pattern) i.next() ) )
- return true;
- }
- }
-
- return false;
- }
-
- private static boolean isMetadata( String link )
- {
- return link.startsWith("{SET");
- }
-
- /**
- * Returns true, if the argument contains a number, otherwise false.
- * In a quick test this is roughly the same speed as Integer.parseInt()
- * if the argument is a number, and roughly ten times the speed, if
- * the argument is NOT a number.
- */
-
- private boolean isNumber( String s )
- {
- if( s == null ) return false;
-
- if( s.length() > 1 && s.charAt(0) == '-' )
- s = s.substring(1);
-
- for( int i = 0; i < s.length(); i++ )
- {
- if( !Character.isDigit(s.charAt(i)) )
- return false;
- }
-
- return true;
- }
-
- /**
- * Checks for the existence of a traditional style CamelCase link.
- * <P>
- * We separate all white-space -separated words, and feed it to this
- * routine to find if there are any possible camelcase links.
- * For example, if "word" is "__HyperLink__" we return "HyperLink".
- *
- * @param word A phrase to search in.
- * @return The match within the phrase. Returns null, if no CamelCase
- * hyperlink exists within this phrase.
- */
- private String checkForCamelCaseLink( String word )
- {
- PatternMatcherInput input;
-
- input = new PatternMatcherInput( word );
-
- if( m_matcher.contains( input, m_camelCasePtrn ) )
- {
- MatchResult res = m_matcher.getMatch();
-
- String link = res.group(2);
-
- if( res.group(1) != null )
- {
- if( res.group(1).endsWith("~") ||
- res.group(1).indexOf('[') != -1 )
- {
- // Delete the (~) from beginning.
- // We'll make '~' the generic kill-processing-character from
- // now on.
- return null;
- }
- }
-
- return link;
- } // if match
-
- return null;
- }
-
- /**
- * When given a link to a WikiName, we just return
- * a proper HTML link for it. The local link mutator
- * chain is also called.
- */
- private String makeCamelCaseLink( String wikiname )
- {
- String matchedLink;
- String link;
-
- callMutatorChain( m_localLinkMutatorChain, wikiname );
-
- if( (matchedLink = linkExists( wikiname )) != null )
- {
- link = makeLink( READ, matchedLink, wikiname );
- }
- else
- {
- link = makeLink( EDIT, wikiname, wikiname );
- }
-
- return link;
+ return MarkupParser.cleanLink( link );
}
- private String makeDirectURILink( String url )
+ private StringReader m_data;
+
+ /** {@inheritDoc} */
+ public int read()
+ throws IOException
{
- String last = "";
- String result;
-
- if( url.endsWith(",") || url.endsWith(".") )
- {
- last = url.substring( url.length()-1 );
- url = url.substring( 0, url.length()-1 );
- }
-
- callMutatorChain( m_externalLinkMutatorChain, url );
-
- if( isImageLink( url ) )
- {
- result = handleImageLink( url, url, false );
- }
- else
+ if( m_data == null )
{
- result = makeLink( EXTERNAL, url, url ) + m_renderer.outlinkImage();
+ WikiRenderer r = new XHTMLRenderer( m_context, m_parser.parse() );
+
+ String s = r.getString();
+
+ m_data = new StringReader( s );
}
- result += last;
-
- return result;
+ return m_data.read();
}
- /**
- * Image links are handled differently:
- * 1. If the text is a WikiName of an existing page,
- * it gets linked.
- * 2. If the text is an external link, then it is inlined.
- * 3. Otherwise it becomes an ALT text.
- *
- * @param reallink The link to the image.
- * @param link Link text portion, may be a link to somewhere else.
- * @param hasLinkText If true, then the defined link had a link text available.
- * This means that the link text may be a link to a wiki page,
- * or an external resource.
- */
-
- private String handleImageLink( String reallink, String link, boolean hasLinkText )
+ /** {@inheritDoc} */
+ public int read( char[] buf, int off, int len )
+ throws IOException
{
- String possiblePage = cleanLink( link );
- String res = "";
-
- if( isExternalLink( link ) && hasLinkText )
- {
- res = makeLink( IMAGELINK, reallink, link );
- }
- else if( ( linkExists( possiblePage ) ) != null &&
- hasLinkText )
- {
- // System.out.println("Orig="+link+", Matched: "+matchedLink);
- callMutatorChain( m_localLinkMutatorChain, possiblePage );
-
- res = makeLink( IMAGEWIKILINK, reallink, link );
- }
- else
- {
- res = makeLink( IMAGE, reallink, link );
- }
-
- return res;
+ return m_data.read( buf, off, len );
}
-
- private String handleAccessRule( String ruleLine )
+
+ /** {@inheritDoc} */
+ public boolean ready()
+ throws IOException
{
- if( !m_parseAccessRules ) return "";
- Acl acl;
- WikiPage page = m_context.getPage();
- // UserDatabase db = m_context.getEngine().getUserDatabase();
-
- if( ruleLine.startsWith( "{" ) )
- ruleLine = ruleLine.substring( 1 );
- if( ruleLine.endsWith( "}" ) )
- ruleLine = ruleLine.substring( 0, ruleLine.length() - 1 );
-
- log.debug("page="+page.getName()+", ACL = "+ruleLine);
-
- try
- {
- acl = m_engine.getAclManager().parseAcl( page, ruleLine );
-
- page.setAcl( acl );
-
- log.debug( acl.toString() );
- }
- catch( WikiSecurityException wse )
- {
- return m_renderer.makeError( wse.getMessage() );
- }
-
- return "";
+ return m_data.ready();
}
-
- /**
- * Handles metadata setting [{SET foo=bar}]
- */
- private String handleMetadata( String link )
+
+ /** {@inheritDoc} */
+ public void close()
{
- try
- {
- String args = link.substring( link.indexOf(' '), link.length()-1 );
-
- String name = args.substring( 0, args.indexOf('=') );
- String val = args.substring( args.indexOf('=')+1, args.length() );
-
- name = name.trim();
- val = val.trim();
-
- if( val.startsWith("'") ) val = val.substring( 1 );
- if( val.endsWith("'") ) val = val.substring( 0, val.length()-1 );
-
- // log.debug("SET name='"+name+"', value='"+val+"'.");
-
- if( name.length() > 0 && val.length() > 0 )
- {
- val = m_engine.getVariableManager().expandVariables( m_context,
- val );
-
- m_context.getPage().setAttribute( name, val );
- }
- }
- catch( Exception e )
- {
- ResourceBundle rb = m_context.getBundle(InternationalizationManager.CORE_BUNDLE);
- Object[] args = { link };
- m_renderer.makeError( MessageFormat.format( rb.getString( "markupparser.error.invalidset" ), args ) );
- }
-
- return "";
}
- /**
- * Gobbles up all hyperlinks that are encased in square brackets.
- */
- private String handleHyperlinks( String link )
- {
- StringBuffer sb = new StringBuffer();
- String reallink;
- int cutpoint;
-
- if( isAccessRule( link ) )
- {
- return handleAccessRule( link );
- }
-
- if( isMetadata( link ) )
- {
- return handleMetadata( link );
- }
-
- if( PluginManager.isPluginLink( link ) )
- {
- String included = "";
- try
- {
- if( m_enablePlugins )
- {
- included = m_engine.getPluginManager().execute( m_context, link );
- }
- }
- catch( PluginException e )
- {
- log.info( "Failed to insert plugin", e );
- log.info( "Root cause:",e.getRootThrowable() );
-
- ResourceBundle rb = m_context.getBundle(WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE);
- Object[] args = { e.getMessage() };
-
- included = m_renderer.makeError( MessageFormat.format( rb.getString( "plugin.error.insertionfailed" ), args ) );
- }
-
- sb.append( included );
-
- return sb.toString();
- }
-
- link = TextUtil.replaceEntities( link );
-
- if( (cutpoint = link.indexOf('|')) != -1 )
- {
- reallink = link.substring( cutpoint+1 ).trim();
- link = link.substring( 0, cutpoint );
- }
- else
- {
- reallink = link.trim();
- }
-
- int interwikipoint = -1;
-
- //
- // Yes, we now have the components separated.
- // link = the text the link should have
- // reallink = the url or page name.
- //
- // In many cases these are the same. [link|reallink].
- //
- if( VariableManager.isVariableLink( link ) )
- {
- String value;
-
- try
- {
- value = m_engine.getVariableManager().parseAndGetValue( m_context, link );
- }
- catch( NoSuchVariableException e )
- {
- value = m_renderer.makeError(e.getMessage());
- }
- catch( IllegalArgumentException e )
- {
- value = m_renderer.makeError(e.getMessage());
- }
-
- sb.append( value );
- }
- else if( isExternalLink( reallink ) )
- {
- // It's an external link, out of this Wiki
-
- callMutatorChain( m_externalLinkMutatorChain, reallink );
-
- if( isImageLink( reallink ) )
- {
- sb.append( handleImageLink( reallink, link, (cutpoint != -1) ) );
- }
- else
- {
- sb.append( makeLink( EXTERNAL, reallink, link ) );
- sb.append( m_renderer.outlinkImage() );
- }
- }
- else if( (interwikipoint = reallink.indexOf(":")) != -1 )
- {
- // It's an interwiki link
- // InterWiki links also get added to external link chain
- // after the links have been resolved.
-
- // FIXME: There is an interesting issue here: We probably should
- // URLEncode the wikiPage, but we can't since some of the
- // Wikis use slashes (/), which won't survive URLEncoding.
- // Besides, we don't know which character set the other Wiki
- // is using, so you'll have to write the entire name as it appears
- // in the URL. Bugger.
-
- String extWiki = reallink.substring( 0, interwikipoint );
- String wikiPage = reallink.substring( interwikipoint+1 );
-
- String urlReference = m_engine.getInterWikiURL( extWiki );
-
- if( urlReference != null )
- {
- urlReference = TextUtil.replaceString( urlReference, "%s", wikiPage );
- callMutatorChain( m_externalLinkMutatorChain, urlReference );
-
- sb.append( makeLink( INTERWIKI, urlReference, link ) );
-
- if( isExternalLink(urlReference) )
- {
- sb.append( m_renderer.outlinkImage() );
- }
- }
- else
- {
- ResourceBundle rb = m_context.getBundle(WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE);
- Object[] args = { extWiki };
-
- sb.append( link+" "+m_renderer.makeError( MessageFormat.format( rb.getString( "plugin.error.nointerwikiref" ), args ) ) );
- }
- }
- else if( reallink.startsWith("#") )
- {
- // It defines a local footnote
- sb.append( makeLink( LOCAL, reallink, link ) );
- }
- else if( isNumber( reallink ) )
- {
- // It defines a reference to a local footnote
- sb.append( makeLink( LOCALREF, reallink, link ) );
- }
- else
- {
- int hashMark = -1;
-
- //
- // Internal wiki link, but is it an attachment link?
- //
- String attachment = findAttachment( reallink );
- if( attachment != null )
- {
- callMutatorChain( m_attachmentLinkMutatorChain, attachment );
-
- if( isImageLink( reallink ) )
- {
- attachment = m_context.getContext().getURL( AttachActionBean.class, attachment );
- sb.append( handleImageLink( attachment, link, (cutpoint != -1) ) );
- }
- else
- {
- sb.append( makeLink( ATTACHMENT, attachment, link ) );
- }
- }
- else if( (hashMark = reallink.indexOf('#')) != -1 )
- {
- // It's an internal Wiki link, but to a named section
-
- String namedSection = reallink.substring( hashMark+1 );
- reallink = reallink.substring( 0, hashMark );
-
- reallink = cleanLink( reallink );
-
- callMutatorChain( m_localLinkMutatorChain, reallink );
-
- String matchedLink;
- if( (matchedLink = linkExists( reallink )) != null )
- {
- String sectref = "section-"+m_engine.encodeName(matchedLink)+"-"+namedSection;
- sectref = sectref.replace('%', '_');
- sb.append( makeLink( READ, matchedLink, link, sectref ) );
- }
- else
- {
- sb.append( makeLink( EDIT, reallink, link ) );
- }
- }
- else
- {
- // It's an internal Wiki link
- reallink = cleanLink( reallink );
-
- callMutatorChain( m_localLinkMutatorChain, reallink );
-
- String matchedLink = linkExists( reallink );
-
- if( matchedLink != null )
- {
- sb.append( makeLink( READ, matchedLink, link ) );
- }
- else
- {
- sb.append( makeLink( EDIT, reallink, link ) );
- }
- }
- }
-
- return sb.toString();
- }
-
- private String findAttachment( String link )
- {
- AttachmentManager mgr = m_engine.getAttachmentManager();
- Attachment att = null;
-
- try
- {
- att = mgr.getAttachmentInfo( m_context, link );
- }
- catch( ProviderException e )
- {
- log.warn("Finding attachments failed: ",e);
- return null;
- }
-
- if( att != null )
- {
- return att.getName();
- }
- else if( link.indexOf('/') != -1 )
- {
- return link;
- }
-
- return null;
- }
-
- /**
- * Closes all annoying lists and things that the user might've
- * left open.
- */
- private String closeAll()
- {
- StringBuffer buf = new StringBuffer();
-
- if( m_isbold )
- {
- buf.append(m_renderer.closeTextEffect(BOLD));
- m_isbold = false;
- }
-
- if( m_isitalic )
- {
- buf.append(m_renderer.closeTextEffect(ITALIC));
- m_isitalic = false;
- }
-
- if( m_isTypedText )
- {
- buf.append(m_renderer.closeTextEffect(TYPED));
- m_isTypedText = false;
- }
-
- /*
- for( ; m_listlevel > 0; m_listlevel-- )
- {
- buf.append( "</ul>\n" );
- }
-
- for( ; m_numlistlevel > 0; m_numlistlevel-- )
- {
- buf.append( "</ol>\n" );
- }
- */
- // cleanup OL and UL lists
- buf.append(unwindGeneralList());
-
- if( m_isPre )
- {
- buf.append(m_renderer.closePreformatted());
- m_isEscaping = false;
- m_isPre = false;
- }
-
- if( m_istable )
- {
- buf.append( m_renderer.closeTable() );
- m_istable = false;
- }
-
- if( m_isOpenParagraph )
- {
- buf.append( m_renderer.closeParagraph() );
- m_isOpenParagraph = false;
- }
-
- return buf.toString();
- }
-
-
- private int nextToken()
- throws IOException
- {
- if( m_in == null ) return -1;
- return m_in.read();
- }
-
- /**
- * Push back any character to the current input. Does not
- * push back a read EOF, though.
- */
- private void pushBack( int c )
- throws IOException
- {
- if( c != -1 && m_in != null )
- {
- m_in.unread( c );
- }
- }
-
- /**
- * Pushes back any string that has been read. It will obviously
- * be pushed back in a reverse order.
- *
- * @since 2.1.77
- */
- private void pushBack( String s )
- throws IOException
- {
- for( int i = s.length()-1; i >= 0; i-- )
- {
- pushBack( s.charAt(i) );
- }
- }
-
- private String handleBackslash()
- throws IOException
- {
- int ch = nextToken();
-
- if( ch == '\\' )
- {
- int ch2 = nextToken();
-
- if( ch2 == '\\' )
- {
- return m_renderer.lineBreak(true);
- }
-
- pushBack( ch2 );
-
- return m_renderer.lineBreak(false);
- }
-
- pushBack( ch );
-
- return "\\";
- }
-
- private String handleUnderscore()
- throws IOException
- {
- int ch = nextToken();
- String res = "_";
-
- if( ch == '_' )
- {
- res = m_isbold ? m_renderer.closeTextEffect(BOLD) : m_renderer.openTextEffect(BOLD);
- m_isbold = !m_isbold;
- }
- else
- {
- pushBack( ch );
- }
-
- return res;
- }
-
- /**
- * For example: italics.
- */
- private String handleApostrophe()
- throws IOException
- {
- int ch = nextToken();
- String res = "'";
-
- if( ch == '\'' )
- {
- res = m_isitalic ? m_renderer.closeTextEffect(ITALIC) : m_renderer.openTextEffect(ITALIC);
- m_isitalic = !m_isitalic;
- }
- else
- {
- pushBack( ch );
- }
-
- return res;
- }
-
- private String handleOpenbrace( boolean isBlock )
- throws IOException
- {
- int ch = nextToken();
- String res = "{";
-
- if( ch == '{' )
- {
- int ch2 = nextToken();
-
- if( ch2 == '{' )
- {
- res = startBlockLevel()+m_renderer.openPreformatted( isBlock );
- m_isPre = true;
- m_isEscaping = true;
- }
- else
- {
- pushBack( ch2 );
-
- res = m_renderer.openTextEffect(TYPED);
- m_isTypedText = true;
- }
- }
- else
- {
- pushBack( ch );
- }
-
- return res;
- }
-
- /**
- * Handles both }} and }}}
- */
- private String handleClosebrace()
- throws IOException
- {
- String res = "}";
-
- int ch2 = nextToken();
-
- if( ch2 == '}' )
- {
- int ch3 = nextToken();
-
- if( ch3 == '}' )
- {
- if( m_isPre )
- {
- m_isPre = false;
- m_isEscaping = false;
- res = m_renderer.closePreformatted();
- }
- else
- {
- res = "}}}";
- }
- }
- else
- {
- pushBack( ch3 );
-
- if( !m_isEscaping )
- {
- res = m_renderer.closeTextEffect(TYPED);
- m_isTypedText = false;
- }
- else
- {
- pushBack( ch2 );
- }
- }
- }
- else
- {
- pushBack( ch2 );
- }
-
- return res;
- }
-
- private String handleDash()
- throws IOException
- {
- int ch = nextToken();
-
- if( ch == '-' )
- {
- int ch2 = nextToken();
-
- if( ch2 == '-' )
- {
- int ch3 = nextToken();
-
- if( ch3 == '-' )
- {
- // Empty away all the rest of the dashes.
- // Do not forget to return the first non-match back.
- while( (ch = nextToken()) == '-' );
-
- pushBack(ch);
- return startBlockLevel()+m_renderer.makeRuler();
- }
-
- pushBack( ch3 );
- }
- pushBack( ch2 );
- }
-
- pushBack( ch );
-
- return "-";
- }
-
- /**
- * This method peeks ahead in the stream until EOL and returns the result.
- * It will keep the buffers untouched.
- *
- * @return The string from the current position to the end of line.
- */
-
- // FIXME: Always returns an empty line, even if the stream is full.
- private String peekAheadLine()
- throws IOException
- {
- String s = readUntilEOL().toString();
- pushBack( s );
-
- return s;
- }
-
- private String handleHeading()
- throws IOException
- {
- StringBuffer buf = new StringBuffer();
-
- int ch = nextToken();
-
- Heading hd = new Heading();
-
- if( ch == '!' )
- {
- int ch2 = nextToken();
-
- if( ch2 == '!' )
- {
- String title = peekAheadLine();
-
- buf.append( m_renderer.makeHeading( Heading.HEADING_LARGE, title, hd) );
- }
- else
- {
- pushBack( ch2 );
- String title = peekAheadLine();
- buf.append( m_renderer.makeHeading( Heading.HEADING_MEDIUM, title, hd ) );
- }
- }
- else
- {
- pushBack( ch );
- String title = peekAheadLine();
- buf.append( m_renderer.makeHeading( Heading.HEADING_SMALL, title, hd ) );
- }
-
- callHeadingListenerChain( hd );
-
- return buf.toString();
- }
-
- /**
- * Reads the stream until the next EOL or EOF. Note that it will also read the
- * EOL from the stream.
- */
- private StringBuffer readUntilEOL()
- throws IOException
- {
- int ch;
- StringBuffer buf = new StringBuffer();
-
- while( true )
- {
- ch = nextToken();
-
- if( ch == -1 )
- break;
-
- buf.append( (char) ch );
-
- if( ch == '\n' )
- break;
- }
-
- return buf;
- }
-
- /**
- * Starts a block level element, therefore closing the
- * a potential open paragraph tag.
- */
- private String startBlockLevel()
- {
- if( m_isOpenParagraph )
- {
- m_isOpenParagraph = false;
- return m_renderer.closeParagraph();
- }
-
- return "";
- }
-
- /**
- * Like original handleOrderedList() and handleUnorderedList()
- * however handles both ordered ('#') and unordered ('*') mixed together.
- */
-
- // FIXME: Refactor this; it's a bit messy.
-
- private String handleGeneralList()
- throws IOException
- {
- StringBuffer buf = new StringBuffer();
-
- buf.append( startBlockLevel() );
-
- String strBullets = readWhile( "*#" );
- // String strBulletsRaw = strBullets; // to know what was original before phpwiki style substitution
- int numBullets = strBullets.length();
-
- // override the beginning portion of bullet pattern to be like the previous
- // to simulate PHPWiki style lists
-
- if(m_allowPHPWikiStyleLists)
- {
- // only substitute if different
- if(!( strBullets.substring(0,Math.min(numBullets,m_genlistlevel)).equals
- (m_genlistBulletBuffer.substring(0,Math.min(numBullets,m_genlistlevel)) ) ) )
- {
- if(numBullets <= m_genlistlevel)
- {
- // Substitute all but the last character (keep the expressed bullet preference)
- strBullets = (numBullets > 1 ? m_genlistBulletBuffer.substring(0, numBullets-1) : "")
- + strBullets.substring(numBullets-1, numBullets);
- }
- else
- {
- strBullets = m_genlistBulletBuffer + strBullets.substring(m_genlistlevel, numBullets);
- }
- }
- }
-
- //
- // Check if this is still of the same type
- //
- if( strBullets.substring(0,Math.min(numBullets,m_genlistlevel)).equals
- (m_genlistBulletBuffer.substring(0,Math.min(numBullets,m_genlistlevel)) ) )
- {
- if( numBullets > m_genlistlevel )
- {
- buf.append( m_renderer.openList(strBullets.charAt(m_genlistlevel++)) );
-
- for( ; m_genlistlevel < numBullets; m_genlistlevel++ )
- {
- // bullets are growing, get from new bullet list
- buf.append( m_renderer.openListItem() );
- buf.append( m_renderer.openList(strBullets.charAt(m_genlistlevel)) );
- }
- }
- else if( numBullets < m_genlistlevel )
- {
- // Close the previous list item.
- buf.append( m_renderer.closeListItem() );
-
- for( ; m_genlistlevel > numBullets; m_genlistlevel-- )
- {
- // bullets are shrinking, get from old bullet list
- buf.append( m_renderer.closeList(m_genlistBulletBuffer.charAt(m_genlistlevel - 1)) );
- if( m_genlistlevel > 0 ) buf.append( m_renderer.closeListItem() );
-
- }
- }
- else
- {
- if( m_genlistlevel > 0 ) buf.append( m_renderer.closeListItem() );
- }
- }
- else
- {
- //
- // The pattern has changed, unwind and restart
- //
- int numEqualBullets;
- int numCheckBullets;
-
- // find out how much is the same
- numEqualBullets = 0;
- numCheckBullets = Math.min(numBullets,m_genlistlevel);
-
- while( numEqualBullets < numCheckBullets )
- {
- // if the bullets are equal so far, keep going
- if( strBullets.charAt(numEqualBullets) == m_genlistBulletBuffer.charAt(numEqualBullets))
- numEqualBullets++;
- // otherwise giveup, we have found how many are equal
- else
- break;
- }
-
- //unwind
- for( ; m_genlistlevel > numEqualBullets; m_genlistlevel-- )
- {
- buf.append( m_renderer.closeList( m_genlistBulletBuffer.charAt(m_genlistlevel - 1) ) );
- if( m_genlistlevel > 0 ) buf.append( m_renderer.closeListItem() );
- }
-
- //rewind
- buf.append( m_renderer.openList( strBullets.charAt(numEqualBullets++) ) );
- for(int i = numEqualBullets; i < numBullets; i++)
- {
- buf.append( m_renderer.openListItem() );
- buf.append( m_renderer.openList( strBullets.charAt(i) ) );
- }
- m_genlistlevel = numBullets;
- }
- buf.append( m_renderer.openListItem() );
-
- // work done, remember the new bullet list (in place of old one)
- m_genlistBulletBuffer.setLength(0);
- m_genlistBulletBuffer.append(strBullets);
-
- return buf.toString();
- }
-
- private String unwindGeneralList()
- {
- // String cStrShortName = "unwindGeneralList()";
-
- StringBuffer buf = new StringBuffer();
-
- //unwind
- for( ; m_genlistlevel > 0; m_genlistlevel-- )
- {
- buf.append(m_renderer.closeListItem());
- buf.append( m_renderer.closeList( m_genlistBulletBuffer.charAt(m_genlistlevel - 1) ) );
- }
-
- m_genlistBulletBuffer.setLength(0);
-
- return buf.toString();
- }
-
-
- private String handleDefinitionList()
- throws IOException
- {
- if( !m_isdefinition )
- {
- m_isdefinition = true;
-
- m_closeTag = m_renderer.closeDefinitionItem()+m_renderer.closeDefinitionList();
-
- return startBlockLevel()+m_renderer.openDefinitionList()+m_renderer.openDefinitionTitle();
- }
-
- return ";";
- }
-
- private String handleOpenbracket()
- throws IOException
- {
- StringBuffer sb = new StringBuffer();
- int ch;
- boolean isPlugin = false;
-
- while( (ch = nextToken()) == '[' )
- {
- sb.append( (char)ch );
- }
-
- if( ch == '{' )
- {
- isPlugin = true;
- }
-
- pushBack( ch );
-
- if( sb.length() > 0 )
- {
- return sb.toString();
- }
-
- //
- // Find end of hyperlink
- //
-
- ch = nextToken();
-
- while( ch != -1 )
- {
- if( ch == ']' && (!isPlugin || sb.charAt( sb.length()-1 ) == '}' ) )
- {
- break;
- }
-
- sb.append( (char) ch );
-
- ch = nextToken();
- }
-
- if( ch == -1 )
- {
- log.debug("Warning: unterminated link detected!");
- return sb.toString();
- }
-
- return handleHyperlinks( sb.toString() );
- }
-
- /**
- * Reads the stream until the current brace is closed or stream end.
- */
- private String readBraceContent( char opening, char closing )
- throws IOException
- {
- StringBuffer sb = new StringBuffer();
- int braceLevel = 1;
- int ch;
- while(( ch = nextToken() ) != -1 )
- {
- if( ch == '\\' )
- {
- continue;
- }
- else if ( ch == opening )
- {
- braceLevel++;
- }
- else if ( ch == closing )
- {
- braceLevel--;
- if (braceLevel==0)
- {
- break;
- }
- }
- sb.append( (char)ch );
- }
- return sb.toString();
- }
-
- /**
- * Reads the stream until it meets one of the specified
- * ending characters, or stream end. The ending character will be left
- * in the stream.
- */
- private String readUntil( String endChars )
- throws IOException
- {
- StringBuffer sb = new StringBuffer();
- int ch = nextToken();
-
- while( ch != -1 )
- {
- if( ch == '\\' )
- {
- ch = nextToken();
- if( ch == -1 )
- {
- break;
- }
- }
- else
- {
- if( endChars.indexOf((char)ch) != -1 )
- {
- pushBack( ch );
- break;
- }
- }
- sb.append( (char) ch );
- ch = nextToken();
- }
-
- return sb.toString();
- }
-
- /**
- * Reads the stream while the characters that have been specified are
- * in the stream, returning then the result as a String.
- */
- private String readWhile( String endChars )
- throws IOException
- {
- StringBuffer sb = new StringBuffer();
- int ch = nextToken();
-
- while( ch != -1 )
- {
- if( endChars.indexOf((char)ch) == -1 )
- {
- pushBack( ch );
- break;
- }
-
- sb.append( (char) ch );
- ch = nextToken();
- }
-
- return sb.toString();
- }
-
-
- /**
- * Handles constructs of type %%(style) and %%class
- * @param newLine
- * @return
- * @throws IOException
- */
- private String handleDiv( boolean newLine )
- throws IOException
- {
- int ch = nextToken();
-
- if( ch == '%' )
- {
- StringBuffer sb = new StringBuffer();
-
- String style = null;
- String clazz = null;
-
- ch = nextToken();
-
- //
- // Style or class?
- //
- if( ch == '(' )
- {
- style = readBraceContent('(',')');
- }
- else if( Character.isLetter( (char) ch ) )
- {
- pushBack( ch );
- clazz = readUntil( " \t\n\r" );
- ch = nextToken();
-
- //
- // Pop out only spaces, so that the upcoming EOL check does not check the
- // next line.
- //
- if( ch == '\n' || ch == '\r' )
- {
- pushBack(ch);
- }
- }
- else
- {
- //
- // Anything else stops.
- //
-
- pushBack(ch);
-
- try
- {
- Boolean isSpan = (Boolean)m_styleStack.pop();
-
- if( isSpan == null )
- {
- // Fail quietly
- }
- else if( isSpan.booleanValue() )
- {
- sb.append( m_renderer.closeSpan() );
- }
- else
- {
- sb.append( m_renderer.closeDiv() );
- }
- }
- catch( EmptyStackException e )
- {
- log.debug("Page '"+m_context.getPage().getName()+"' closes a %%-block that has not been opened.");
- }
-
- return sb.toString();
- }
-
- //
- // Decide if we should open a div or a span?
- //
- String eol = peekAheadLine();
-
- if( eol.trim().length() > 0 )
- {
- // There is stuff after the class
-
- sb.append( m_renderer.openSpan( style, clazz ) );
-
- m_styleStack.push( Boolean.TRUE );
- }
- else
- {
- sb.append( startBlockLevel() );
- sb.append( m_renderer.openDiv( style, clazz ) );
- m_styleStack.push( Boolean.FALSE );
- }
-
- return sb.toString();
- }
-
- pushBack(ch);
-
- return "%";
- }
-
- private String handleBar( boolean newLine )
- throws IOException
- {
- StringBuffer sb = new StringBuffer();
-
- if( !m_istable && !newLine )
- {
- return "|";
- }
-
- if( newLine )
- {
- if( !m_istable )
- {
- sb.append( startBlockLevel() );
- sb.append( m_renderer.openTable() );
- m_istable = true;
- }
-
- sb.append( m_renderer.openTableRow() );
- m_closeTag = m_renderer.closeTableItem()+m_renderer.closeTableRow();
- }
-
- int ch = nextToken();
-
- if( ch == '|' )
- {
- if( !newLine )
- {
- sb.append( m_renderer.closeTableHeading() );
- }
- sb.append( m_renderer.openTableHeading() );
- m_closeTag = m_renderer.closeTableHeading()+m_renderer.closeTableRow();
- }
- else
- {
- if( !newLine )
- {
- sb.append( m_renderer.closeTableItem() );
- }
- sb.append( m_renderer.openTableItem() );
- pushBack( ch );
- }
-
- return sb.toString();
- }
-
- /**
- * Generic escape of next character or entity.
- */
- private String handleTilde()
- throws IOException
- {
- int ch = nextToken();
-
- if( ch == '|' || ch == '~' || ch == '\\' || ch == '*' || ch == '#' ||
- ch == '-' || ch == '!' || ch == '\'' || ch == '_' || ch == '[' ||
- ch == '{' || ch == ']' || ch == '}' )
- {
- StringBuffer sb = new StringBuffer();
- sb.append( (char)ch );
- sb.append(readWhile( ""+(char)ch ));
- return sb.toString();
- }
-
- if( Character.isUpperCase( (char) ch ) )
- {
- pushBack( ch );
- return "";
- }
-
- // No escape.
- pushBack( ch );
-
- return "~";
- }
-
- private void fillBuffer()
- throws IOException
- {
- StringBuffer buf = new StringBuffer();
- StringBuffer word = null;
- int previousCh = -2;
- int start = 0;
-
- boolean quitReading = false;
- boolean newLine = true; // FIXME: not true if reading starts in middle of buffer
-
- while(!quitReading)
- {
- int ch = nextToken();
- String s = null;
-
- //
- // Check if we're actually ending the preformatted mode.
- // We still must do an entity transformation here.
- //
- if( m_isEscaping )
- {
- if( ch == '}' )
- {
- buf.append( handleClosebrace() );
- }
- else if( ch == -1 )
- {
- quitReading = true;
- }
- else
- {
- m_renderer.doChar( buf, (char)ch );
- }
-
- continue;
- }
-
- //
- // CamelCase detection, a non-trivial endeavour.
- // We keep track of all white-space separated entities, which we
- // hereby refer to as "words". We then check for an existence
- // of a CamelCase format text string inside the "word", and
- // if one exists, we replace it with a proper link.
- //
-
- if( m_camelCaseLinks )
- {
- // Quick parse of start of a word boundary.
-
- if( word == null &&
- (Character.isWhitespace( (char)previousCh ) ||
- WORD_SEPARATORS.indexOf( (char)previousCh ) != -1 ||
- newLine ) &&
- !Character.isWhitespace( (char) ch ) )
- {
- word = new StringBuffer();
- }
-
- // Are we currently tracking a word?
- if( word != null )
- {
- //
- // Check for the end of the word.
- //
-
- if( Character.isWhitespace( (char)ch ) ||
- ch == -1 ||
- WORD_SEPARATORS.indexOf( (char) ch ) != -1 )
- {
- String potentialLink = word.toString();
-
- String camelCase = checkForCamelCaseLink(potentialLink);
-
- if( camelCase != null )
- {
- // System.out.println("Buffer is "+buf);
-
- // System.out.println(" Replacing "+camelCase+" with proper link.");
- start = buf.toString().lastIndexOf( camelCase );
- buf.replace(start,
- start+camelCase.length(),
- makeCamelCaseLink(camelCase) );
-
- // System.out.println(" Resulting with "+buf);
- }
- else
- {
- // System.out.println("Checking for potential URI: "+potentialLink);
- if( isExternalLink( potentialLink ) )
- {
- // System.out.println("buf="+buf);
- start = buf.toString().lastIndexOf( potentialLink );
-
- if( start >= 0 )
- {
- String link = readUntil(" \t()[]{}!\"'\n|");
-
- link = potentialLink + (char)ch + link; // Do not forget the start.
-
- // System.out.println("start="+start+", pl="+potentialLink);
-
- buf.replace( start,
- start + potentialLink.length(),
- makeDirectURILink( link ) );
-
- // System.out.println("Resulting with "+buf);
-
- ch = nextToken();
- }
- }
- }
-
- // We've ended a word boundary, so time to reset.
- word = null;
- }
- else
- {
- // This should only be appending letters and digits.
- word.append( (char)ch );
- } // if end of word
- } // if word's not null
-
- // Always set the previous character to test for word starts.
- previousCh = ch;
-
- } // if m_camelCaseLinks
-
- //
- // An empty line stops a list
- //
- if( newLine && ch != '*' && ch != '#' && ch != ' ' && m_genlistlevel > 0 )
- {
- buf.append(unwindGeneralList());
- }
-
- if( newLine && ch != '|' && m_istable )
- {
- buf.append( m_renderer.closeTable() );
- m_istable = false;
- m_closeTag = null;
- }
-
- //
- // Now, check the incoming token.
- //
- switch( ch )
- {
- case '\r':
- // DOS linefeeds we forget
- s = null;
- break;
-
- case '\n':
- //
- // Close things like headings, etc.
- //
- if( m_closeTag != null )
- {
- buf.append( m_closeTag );
- m_closeTag = null;
- }
-
- m_isdefinition = false;
-
- if( newLine )
- {
- // Paragraph change.
- buf.append( startBlockLevel() );
-
- //
- // Figure out which elements cannot be enclosed inside
- // a <p></p> pair according to XHTML rules.
- //
- String nextLine = peekAheadLine();
- if( nextLine.length() == 0 ||
- (nextLine.length() > 0 &&
- !nextLine.startsWith("{{{") &&
- !nextLine.startsWith("----") &&
- !nextLine.startsWith("%%") &&
- "*#!;".indexOf( nextLine.charAt(0) ) == -1) )
- {
- buf.append( m_renderer.openParagraph() );
- m_isOpenParagraph = true;
- }
- }
- else
- {
- buf.append("\n");
- newLine = true;
- }
-
- break;
-
- case '\\':
- s = handleBackslash();
- break;
-
- case '_':
- s = handleUnderscore();
- break;
-
- case '\'':
- s = handleApostrophe();
- break;
-
- case '{':
- s = handleOpenbrace( newLine );
- break;
-
- case '}':
- s = handleClosebrace();
- break;
-
- case '-':
- s = handleDash();
- break;
-
- case '!':
- if( newLine )
- {
- s = handleHeading();
- }
- else
- {
- s = "!";
- }
- break;
-
- case ';':
- if( newLine )
- {
- s = handleDefinitionList();
- }
- else
- {
- s = ";";
- }
- break;
-
- case ':':
- if( m_isdefinition )
- {
- s = m_renderer.closeDefinitionTitle()+m_renderer.openDefinitionItem();
- m_isdefinition = false;
- }
- else
- {
- s = ":";
- }
- break;
-
- case '[':
- s = handleOpenbracket();
- break;
-
- case '*':
- if( newLine )
- {
- pushBack('*');
- s = handleGeneralList();
- }
- else
- {
- s = "*";
- }
- break;
-
- case '#':
- if( newLine )
- {
- pushBack('#');
- s = handleGeneralList();
- }
- else
- {
- s = "#";
- }
- break;
-
- case '|':
- s = handleBar( newLine );
- break;
-
- case '<':
- s = m_allowHTML ? "<" : "<";
- break;
-
- case '>':
- s = m_allowHTML ? ">" : ">";
- break;
-
- case '\"':
- s = m_allowHTML ? "\"" : """;
- break;
-
- /*
- case '&':
- s = "&";
- break;
- */
- case '~':
- s = handleTilde();
- break;
-
- case '%':
- s = handleDiv( newLine );
- break;
-
- case -1:
- if( m_closeTag != null )
- {
- buf.append( m_closeTag );
- m_closeTag = null;
- }
- quitReading = true;
- break;
-
- default:
- buf.append( (char)ch );
- newLine = false;
- break;
- }
-
- if( s != null )
- {
- buf.append( s );
- newLine = false;
- }
-
- }
-
- m_data = new StringReader( buf.toString() );
- }
-
-
- public int read()
- throws IOException
- {
- int val = m_data.read();
-
- if( val == -1 )
- {
- fillBuffer();
- val = m_data.read();
-
- if( val == -1 )
- {
- m_data = new StringReader( closeAll() );
-
- val = m_data.read();
- }
- }
-
- return val;
- }
-
- public int read( char[] buf, int off, int len )
- throws IOException
- {
- return m_data.read( buf, off, len );
- }
-
- public boolean ready()
- throws IOException
- {
- log.debug("ready ? "+m_data.ready() );
- if(!m_data.ready())
- {
- fillBuffer();
- }
-
- return m_data.ready();
- }
-
- public void close()
- {
- }
-
- /**
- * All HTML output stuff is here. This class is a helper class, and will
- * be spawned later on with a proper API of its own so that we can have
- * different kinds of renderers.
- */
-
- // FIXME: Not everything is yet, and in the future this class will be spawned
- // out to be its own class.
- private class HTMLRenderer
- extends TextRenderer
- {
- private boolean m_isPreBlock = false;
- private TranslatorReader m_cleanTranslator;
-
- /*
- FIXME: It's relatively slow to create two TranslatorReaders each time.
- */
- public HTMLRenderer()
- {
- }
-
- /**
- * Does a lazy init. Otherwise, we would get into a situation
- * where HTMLRenderer would try and boot a TranslatorReader before
- * the TranslatorReader it is contained by is up.
- */
- private TranslatorReader getCleanTranslator()
- {
- if( m_cleanTranslator == null )
- {
- WikiContext dummyContext = m_engine.getWikiActionBeanFactory().newViewActionBean( m_context.getPage() );
- m_cleanTranslator = new TranslatorReader( dummyContext,
- null,
- new TextRenderer() );
- m_cleanTranslator.m_allowHTML = true;
- }
-
- return m_cleanTranslator;
- }
-
- public void doChar( StringBuffer buf, char ch )
- {
- if( ch == '<' )
- {
- buf.append("<");
- }
- else if( ch == '>' )
- {
- buf.append(">");
- }
- else if( ch == '&' )
- {
- buf.append("&");
- }
- else
- {
- buf.append( ch );
- }
- }
-
- public String openDiv( String style, String clazz )
- {
- StringBuffer sb = new StringBuffer();
-
- sb.append( "<div" );
- sb.append( style != null ? " style=\""+style+"\"" : "" );
- sb.append( clazz != null ? " class=\""+clazz+"\"" : "" );
- sb.append( ">" );
-
- return sb.toString();
- }
-
- public String openSpan( String style, String clazz )
- {
- StringBuffer sb = new StringBuffer();
-
- sb.append( "<span" );
- sb.append( style != null ? " style=\""+style+"\"" : "" );
- sb.append( clazz != null ? " class=\""+clazz+"\"" : "" );
- sb.append( ">" );
-
- return sb.toString();
- }
-
- public String closeDiv()
- {
- return "</div>";
- }
-
- public String closeSpan()
- {
- return "</span>";
- }
-
- public String openParagraph()
- {
- return "<p>";
- }
-
- public String closeParagraph()
- {
- return "</p>\n";
- }
-
- /**
- * Writes out a text effect
- */
- public String openTextEffect( int effect )
- {
- switch( effect )
- {
- case BOLD:
- return "<b>";
- case ITALIC:
- return "<i>";
- case TYPED:
- return "<tt>";
- }
-
- return "";
- }
-
- public String closeTextEffect( int effect )
- {
- switch( effect )
- {
- case BOLD:
- return "</b>";
- case ITALIC:
- return "</i>";
- case TYPED:
- return "</tt>";
- }
-
- return "";
- }
-
- public String openDefinitionItem()
- {
- return "<dd>";
- }
-
- public String closeDefinitionItem()
- {
- return "</dd>\n";
- }
-
- public String openDefinitionTitle()
- {
- return "<dt>";
- }
- public String closeDefinitionTitle()
- {
- return "</dt>";
- }
-
- public String openDefinitionList()
- {
- return "<dl>\n";
- }
-
- public String closeDefinitionList()
- {
- return "</dl>";
- }
-
-
- /**
- * Write a HTMLized link depending on its type.
- *
- * <p>This jsut calls makeLink() with "section" set to null.
- */
- public String makeLink( int type, String link, String text )
- {
- return makeLink( type, link, text, null );
- }
-
- private final String getURL( Class<? extends WikiActionBean> beanClass, String link )
- {
- return m_context.getContext().getURL( beanClass, link );
- }
-
- /**
- * Write a HTMLized link depending on its type.
- *
- * @param type Type of the link.
- * @param link The actual link.
- * @param text The user-visible text for the link.
- * @param section Which named anchor to point to. This may not have any
- * effect on certain link types. If null, will ignore it.
- */
- public String makeLink( int type, String link, String text, String section )
- {
- String result;
-
- if( text == null ) text = link;
-
- section = (section != null) ? ("#"+section) : "";
-
- // Make sure we make a link name that can be accepted
- // as a valid URL.
-
- String encodedlink = m_engine.encodeName( link );
-
- if( encodedlink.length() == 0 )
- {
- type = EMPTY;
- }
-
- switch(type)
- {
- case READ:
- result = "<a class=\"wikipage\" href=\""+getURL(ViewActionBean.class,
- link)+section+"\">"+text+"</a>";
- break;
-
- case EDIT:
- result = "<a class=\"createpage\" title=\"Create '"+link+"'\" href=\""+
- getURL(EditActionBean.class, link)+"\">"+
- text+"</a>";
- break;
-
- case EMPTY:
- result = "<u>"+text+"</u>";
- break;
-
- //
- // These two are for local references - footnotes and
- // references to footnotes.
- // We embed the page name (or whatever WikiContext gives us)
- // to make sure the links are unique across Wiki.
- //
- case LOCALREF:
- result = "<a class=\"footnoteref\" href=\"#ref-"+
- m_context.getPage().getName()+"-"+
- link+"\">["+text+"]</a>";
- break;
-
- case LOCAL:
- result = "<a class=\"footnote\" name=\"ref-"+
- m_context.getPage().getName()+"-"+
- link.substring(1)+"\">["+text+"]</a>";
- break;
-
- //
- // With the image, external and interwiki types we need to
- // make sure nobody can put in Javascript or something else
- // annoying into the links themselves. We do this by preventing
- // a haxor from stopping the link name short with quotes in
- // fillBuffer().
- //
- case IMAGE:
- result = "<img class=\"inline\" src=\""+link+"\" alt=\""+text+"\" />";
- break;
-
- case IMAGELINK:
- result = "<a href=\""+text+"\"><img class=\"inline\" src=\""+link+"\" alt=\""+text+"\"/></a>";
- break;
-
- case IMAGEWIKILINK:
- String pagelink = getURL(ViewActionBean.class,text);
- result = "<a class=\"wikipage\" href=\""+pagelink+"\"><img class=\"inline\" src=\""+link+"\" alt=\""+text+"\" /></a>";
- break;
-
- case EXTERNAL:
- result = "<a class=\"external\" "+
- (m_useRelNofollow ? "rel=\"nofollow\" " : "")+
- "href=\""+link+section+"\">"+text+"</a>";
- break;
-
- case INTERWIKI:
- result = "<a class=\"interwiki\" href=\""+link+section+"\">"+text+"</a>";
- break;
-
- case ATTACHMENT:
- String attlink = getURL( AttachActionBean.class,
- link );
-
- String infolink = getURL( PageInfoActionBean.class,
- link );
-
- String imglink = getURL( NoneActionBean.class,
- "images/attachment_small.png" );
-
- result = "<a class=\"attachment\" href=\""+attlink+"\">"+text+"</a>"+
- "<a href=\""+infolink+
- "\"><img src=\""+imglink+"\" alt=\"(info)\"/></a>";
- break;
-
- default:
- result = "";
- break;
- }
-
- return result;
- }
-
- /**
- * Writes HTML for error message.
- */
-
- public String makeError( String error )
- {
- return "<span class=\"error\">"+error+"</span>";
- }
-
- /**
- * Emits a vertical line.
- */
-
- public String makeRuler()
- {
- return "<hr />";
- }
-
- /**
- * Modifies the "hd" parameter to contain proper values. Because
- * an "id" tag may only contain [a-zA-Z0-9:_-], we'll replace the
- * % after url encoding with '_'.
- */
- private String makeHeadingAnchor( String baseName, String title, Heading hd )
- {
- hd.m_titleText = title;
- title = cleanLink( title );
- hd.m_titleSection = m_engine.encodeName(title);
- hd.m_titleAnchor = "section-"+m_engine.encodeName(baseName)+
- "-"+hd.m_titleSection;
-
- hd.m_titleAnchor = hd.m_titleAnchor.replace( '%', '_' );
- return hd.m_titleAnchor;
- }
-
- private String makeSectionTitle( String title )
- {
- title = title.trim();
-
- StringWriter outTitle = new StringWriter();
-
- try
- {
- TranslatorReader read = getCleanTranslator();
- read.setInputReader( new StringReader(title) );
- FileUtil.copyContents( read, outTitle );
- }
- catch( IOException e )
- {
- log.fatal("CleanTranslator not working", e);
- throw new InternalWikiException("CleanTranslator not working as expected, when cleaning title"+ e.getMessage() );
- }
-
- return outTitle.toString();
- }
-
- /**
- * Returns XHTML for the start of the heading. Also sets the
- * line-end emitter.
- * @param level
- * @param headings A List to which heading should be added.
- */
- public String makeHeading( int level, String title, Heading hd )
- {
- String res = "";
-
- String pageName = m_context.getPage().getName();
-
- String outTitle = makeSectionTitle( title );
-
- hd.m_level = level;
-
- switch( level )
- {
- case Heading.HEADING_SMALL:
- res = "<h4 id='"+makeHeadingAnchor( pageName, outTitle, hd )+"'>";
- m_closeTag = "</h4>";
- break;
-
- case Heading.HEADING_MEDIUM:
- res = "<h3 id='"+makeHeadingAnchor( pageName, outTitle, hd )+"'>";
- m_closeTag = "</h3>";
- break;
-
- case Heading.HEADING_LARGE:
- res = "<h2 id='"+makeHeadingAnchor( pageName, outTitle, hd )+"'>";
- m_closeTag = "</h2>";
- break;
- }
-
- return res;
- }
-
- /**
- * @param bullet A character detailing which kind of a list
- * we are dealing with here. Options are '#' and '*'.
- */
- public String openList( char bullet )
- {
- String res = "";
-
- if( bullet == '#' )
- res = "<ol>\n";
- else if( bullet == '*' )
- res = "<ul>\n";
- else
- log.info("Warning: unknown bullet character '" + bullet + "' at (+)" );
-
- return res;
- }
-
- public String openListItem()
- {
- return "<li>";
- }
-
- public String closeListItem()
- {
- return "</li>\n";
- }
-
- /**
- * @param bullet A character detailing which kind of a list
- * we are dealing with here. Options are '#' and '*'.
- */
- public String closeList( char bullet )
- {
- String res = "";
-
- if( bullet == '#' )
- {
- res = "</ol>\n";
- }
- else if( bullet == '*' )
- {
- res = "</ul>\n";
- }
- else
- {
- //FIXME unknown character -> error
- log.info("Warning: unknown character in unwind '" + bullet + "'" );
- }
-
- return res;
- }
-
- public String openTable()
- {
- return "<table class=\"wikitable\" border=\"1\">\n";
- }
-
- public String closeTable()
- {
- return "</table>\n";
- }
-
- public String openTableRow()
- {
- return "<tr>";
- }
-
- public String closeTableRow()
- {
- return "</tr>";
- }
-
- public String openTableItem()
- {
- return "<td>";
- }
-
- public String closeTableItem()
- {
- return "</td>";
- }
-
- public String openTableHeading()
- {
- return "<th>";
- }
-
- public String closeTableHeading()
- {
- return "</th>";
- }
-
- public String openPreformatted( boolean isBlock )
- {
- m_isPreBlock = isBlock;
-
- if( isBlock )
- {
- return "<pre>";
- }
-
- return "<span style=\"font-family:monospace; whitespace:pre;\">";
- }
-
- public String closePreformatted()
- {
- if( m_isPreBlock )
- return "</pre>\n";
-
- return "</span>";
- }
-
- /**
- * If outlink images are turned on, returns a link to the outward
- * linking image.
- */
- public String outlinkImage()
- {
- if( m_useOutlinkImage )
- {
- return "<img class=\"outlink\" src=\""+
- getURL( NoneActionBean.class,"images/out.png" )+"\" alt=\"\" />";
- }
-
- return "";
- }
-
- /**
- * @param clear If true, then flushes all thingies.
- */
- public String lineBreak( boolean clear )
- {
- if( clear )
- return "<br clear=\"all\" />";
-
- return "<br />";
- }
-
- } // HTMLRenderer
-
- /**
- * A very simple class for outputting plain text with no
- * formatting.
- */
- public class TextRenderer
- {
- public TextRenderer() {}
-
- public void doChar( StringBuffer buf, char ch )
- {
- buf.append( ch );
- }
-
- public String openDiv( String style, String clazz )
- {
- return "";
- }
-
- public String closeDiv()
- {
- return "";
- }
-
- public String openSpan( String style, String clazz )
- {
- return "";
- }
-
- public String closeSpan()
- {
- return "";
- }
-
- public String openParagraph()
- {
- return "";
- }
-
- public String closeParagraph()
- {
- return "\n\n";
- }
-
- /**
- * Writes out a text effect
- */
- public String openTextEffect( int effect )
- {
- return "";
- }
-
- public String closeTextEffect( int effect )
- {
- return "";
- }
-
- public String openDefinitionItem()
- {
- return " : ";
- }
-
- public String closeDefinitionItem()
- {
- return "\n";
- }
-
[... 191 lines stripped ...]