import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Map; import java.util.Properties; import beansoft.jsp.StringUtil; import com.ecyrd.jspwiki.TextUtil; import com.ecyrd.jspwiki.WikiContext; import com.ecyrd.jspwiki.WikiEngine; import com.ecyrd.jspwiki.WikiProvider; import com.ecyrd.jspwiki.attachment.Attachment; import com.ecyrd.jspwiki.attachment.AttachmentManager; import com.ecyrd.jspwiki.plugin.PluginException; import com.ecyrd.jspwiki.plugin.WikiPlugin; import com.ecyrd.jspwiki.providers.ProviderException; /** * Implements a simple plugin that displays source code in syntax hilighter. * * Parameters: *
lang - Optional, language to use, default is "java".
* _body - Optional, Please put source code to the tag's body.
* version - Optional, the attachment's version, default is latest
* src - Optional, the attachment file name, might with
* full path or not, eg: code.txt or Mypage/code.txt
* file - Optional, file path on the local file system you want
* to read, eg: c:\\My.java or c:/My.java
* (FIXME! This is a great security issue while u put site on internet)
* encoding - Optional, the content's encoding of attachment or
* local file, default to server file system's encoding
* showsrc - Optional, whether display the file/attachment's
* src to the output, default value is "true"
* We load the code content as follow sequence:
* _body > src > file
*
* Security issue:
* if you want let the plugin to read the local file system, please edit
* code2html.properties and change following line:
*
* allowReadLocalFile = false
* to
* allowReadLocalFile = true
* .
* Sample usage:
*
*
* [{Code lang='javascript'
*
* function Package(packageName) { // Package name of this package object
* this.packageName = packageName;
* // Return a description of this package object.
*
* this.toString = function() { return 'Package ' + packageName; } }
* }]
* [{Code file='E:\\OpenSource\\JSPWikiPlugins\\src\\Code.java'}]
*
* [{Code src='Code.java'}]
*
*
*
* Depends: jeditSynx.jar, syntax mode files(XML format).
*
* @author Jacky Liu
* @version 1.1 2006-12-05
*/
public class Code implements WikiPlugin {
/**
* Language param name, default to 'java'.
*/
protected static final String PARAM_LANGUAGE = "lang";
/**
* Param name of attachment page's version.
*/
protected static final String PARAM_VERSION = "version";
/**
* Param name of attachment page's src.
*/
protected static final String PARAM_SRC = "src";
/**
* Param name of local file to be read.
*/
protected static final String PARAM_FILE = "file";
/**
* Param name of encoding of attachment or local file.
* Value: Optional, defalut value is server platform's default encoding.
*/
protected static final String PARAM_ENCODING = "encoding";
/**
* Param name of whether display the src.
*/
protected static final String PARAM_SHOW_SRC = "showsrc";
/**
* The path of the syntax highlight CSS file's url.
*/
protected static final String CSS_URL = "";
private static boolean allowReadLocalFile = false;
// We will load from a config file about whether to let Code2html plugin to
// read files on local file system
static {
try {
Properties props = new Properties();
props.load(Code.class.getResourceAsStream("/code2html.properties"));
allowReadLocalFile = Boolean.valueOf(props.getProperty("allowReadLocalFile")).booleanValue();
} catch (Exception e) {
// TODO: handle exception
}
}
public String execute(WikiContext context, Map params)
throws PluginException {
String code = (String) params.get("_body");
String langCode = (String) params.get(PARAM_LANGUAGE);
String src = getCleanParameter( params, PARAM_SRC );
String file = getCleanParameter( params, PARAM_FILE );
String version = getCleanParameter( params, PARAM_VERSION );
String encoding = getCleanParameter( params, PARAM_ENCODING );
String showSrc = getCleanParameter( params, PARAM_SHOW_SRC );
if(showSrc == null) {
showSrc = "true";
}
String srcHead = "";
// We load _body first, if not, load src, then finally we load the local system's file
if (StringUtil.isEmpty(code)) {
// System.out.println(System.currentTimeMillis() + " Attempting to download att " + src
// + ", version " + version);
// Load attachment second
if(!StringUtil.isEmpty(src)) {
code = getAttachmentContent(context, src, version, encoding);
// Add code src to the output
srcHead = src;
}
// Finally load the local file
else if(!StringUtil.isEmpty(file)) {
code = readFileContent(file, encoding);
// Add file src to the output
srcHead = file;
}
if(StringUtil.isEmpty(code))
{
return "";
}
}
if (StringUtil.isEmpty(langCode)) {
langCode = "java";
}
// Load syntax files
studio.beansoft.syntax.ModeLoader.loadModeCatalog(StringUtil
.getRealFilePath("/modes/catalog"), false);
code = studio.beansoft.syntax.sample.HtmlSyntaxHighlighter
.syntaxTextToHtml(code, langCode);
if (StringUtil.isEmpty(code)) {
return "";
}
if("true".equalsIgnoreCase(showSrc)) {
return CSS_URL + "" + "" + srcHead + ""; } else { return CSS_URL + "
" + code + "
" + code + ""; } } /** * Read attachment file content based on the page name. * @param context * @param page * @param version * @param encoding * @return */ protected String getAttachmentContent(WikiContext context,String page, String version, String encoding) { String msg = "An error occurred. Ouch."; int ver = WikiProvider.LATEST_VERSION; WikiEngine m_engine = context.getEngine(); if(context == null || m_engine == null) { return "Null engine?"; } AttachmentManager mgr = m_engine.getAttachmentManager(); ByteArrayOutputStream out = null; InputStream in = null; try { // System.out.println(System.currentTimeMillis() + " Attempting to download att " + page // + ", version " + version); if (version != null) { ver = Integer.parseInt(version); } // FIXME Hacked by Jacky Liu to fix attachment file name issue, // 2006-11-07 // {{{ page = java.net.URLDecoder.decode(page); // }}} Attachment att = mgr.getAttachmentInfo(context, page, ver); if (att != null) { // // Check if the user has permission for this attachment // Comment by Jacky Liu Dec 6 2006, if add this check, the plugin can be very slow // and read file for many times? Why? FIXME! // // AuthorizationManager authmgr = m_engine.getAuthorizationManager(); // Permission permission = new PagePermission(att, "view"); // if (!authmgr.checkPermission(context.getWikiSession(), // permission)) { // // return "User does not have permission for this"; // } out = new ByteArrayOutputStream(8192); in = mgr.getAttachmentStream(att); int read = 0; byte buffer[] = new byte[8192]; while ((read = in.read(buffer)) > -1) { out.write(buffer, 0, read); } out.flush(); if(encoding != null) { return out.toString(encoding); } return out.toString(); } msg = "Attachment '" + page + "', version " + ver + " does not exist."; } catch (ProviderException pe) { msg = "Provider error: " + pe.getMessage(); return msg; } catch (NumberFormatException nfe) { msg = "Invalid version number (" + version + ")"; return msg; } catch (IOException ioe) { msg = "Error: " + ioe.getMessage(); return msg; } finally { if (in != null) try { in.close(); } catch (Exception e) { } // // Quite often, aggressive clients close the connection when they // have // received the last bits. Therefore, we close the output, but // ignore // any exception that might come out of it. // if (out != null) { try { out.close(); } catch (IOException e) { } } } return null; } /** * This method is used to clean away things like quotation marks which * a malicious user could use to stop processing and insert javascript. */ private static final String getCleanParameter( Map params, String paramId ) { return TextUtil.replaceEntities( (String) params.get( paramId ) ); } /** * Read file content as string based on file path and given encoding. * @param filePath * @param encoding * @return file content */ protected String readFileContent(String filePath, String encoding) { if(!allowReadLocalFile) { return "Your are not allowed to read files by the admin:" + filePath; } BufferedReader bufferedReader = null; try { bufferedReader = (encoding == null) ? new BufferedReader(new InputStreamReader (new FileInputStream(filePath))) : new BufferedReader( new InputStreamReader (new FileInputStream(filePath), encoding)); StringBuffer buff = new StringBuffer(); String line = null; while((line = bufferedReader.readLine()) != null) { buff.append(line).append("\n"); } return buff.toString(); } catch (Exception e) { // TODO: handle exception return "Can't read file" + e + "; file:" + filePath; } finally { try { bufferedReader.close(); } catch (Exception e) { // TODO: handle exception } } } }