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
    			+ "
    " + code + "
    "; } else { return CSS_URL + "
    "  + 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 } } } }