highcharts 1.5 ExportController.java using servlet-api-2.5

Recently we have integrated Moxie Group’s GWT Highchart in our project and ran into the conflict with ExportController’s servlet-api-3.0 multi-part issues.

Like the old GWT does, it uses and includes servlet-api-2.5 or rather jetty 7.  Fortunately our project has already got apache-fileupload in its dependency and we could use the fileitemiterator to read the multi-part items. Changes are made in processrequest(HttpServletRequest request, HttpServletResponse response) and getParameter(HttpServletRequest request, String name) Here comes the modified code:

package com.highcharts.export.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;
import org.mortbay.log.Log;

import com.highcharts.export.util.MimeType;
import com.highcharts.export.util.SVGRasterizer;
import com.highcharts.export.util.SVGRasterizerException;

public class ExportController extends HttpServlet
{
private static final long serialVersionUID = 1L;

private static final String REQUEST_METHOD_POST = "POST";

private static final String CONTENT_TYPE_MULTIPART = "multipart/";

private static final String FORBIDDEN_WORD = "<!ENTITY";

protected static Logger logger = Logger.getLogger("exportservlet");

public ExportController()
{
super();
}

public void init()
{
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
processrequest(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
processrequest(request, response);
}

public void processrequest(HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException
{
String svg = getParameter(request, "svg");
String filename = getFilename(getParameter(request, "filename"));
Float width = getWidth(getParameter(request, "width"));
MimeType mime = getMime(getParameter(request, "type"));

try
{
boolean multi = isMultipartRequest(request);

if (multi)
{
try
{
final FileItemFactory factory = new DiskFileItemFactory();
final ServletFileUpload upload = new ServletFileUpload(factory);
final FileItemIterator filesIterator = upload.getItemIterator(request);
while (filesIterator.hasNext())
{
final FileItemStream item = filesIterator.next();
final String name = item.getFieldName();
if ("svg".equals(name))
{
svg = new String(toByteArray(item), "UTF-8");
} else if ("filename".equals(name))
{
filename = getFilename(new String(toByteArray(item), "UTF-8"));
} else if ("width".equals(name))
{
width = getWidth(new String(toByteArray(item), "UTF-8"));
} else if ("type".equals(name))
{
mime = getMime(new String(toByteArray(item), "UTF-8"));
}
}
} catch (Exception e)
{
Log.warn("Failed to parse multi-part parameter: " + e);
}
} else
{

}
if (svg == null || svg.isEmpty())
{
throw new ServletException("The required - svg - post parameter is missing");
}
if (svg.indexOf(FORBIDDEN_WORD) > -1 || svg.indexOf(FORBIDDEN_WORD.toLowerCase()) > -1)
{
throw new ServletException("The - svg - post parameter could contain a malicious attack");
}

ExportController.writeFileContentToHttpResponse(svg, filename, width, mime, response);

} catch (IOException ioe)
{
logger.error("Oops something happened here redirect to error-page, " + ioe.getMessage());
sendError(request, response, ioe);
} catch (ServletException sce)
{
logger.error("Oops something happened here redirect to error-page, " + sce.getMessage());
sendError(request, response, sce);
}
}

public static byte[] toByteArray(final FileItemStream item) throws IOException
{
final InputStream in = item.openStream();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
copy(in, out);
final byte[] byteArray = out.toByteArray();
in.close();
return byteArray;
}

public static void copy(final InputStream in, final OutputStream out) throws IOException
{
final byte[] buf = new byte[1024 * 8];
while (true)
{
final int length = in.read(buf);
if (length == -1)
{
break;
}
out.write(buf, 0, length);
}
out.flush();
}

/*
* Util methods
*/

public static void writeFileContentToHttpResponse(String svg, String filename, Float width, MimeType mime,
HttpServletResponse response) throws IOException, ServletException
{

ByteArrayOutputStream stream = new ByteArrayOutputStream();

if (!MimeType.SVG.equals(mime))
{
try
{
stream = SVGRasterizer.getInstance().transcode(stream, svg, mime, width);
} catch (SVGRasterizerException sre)
{
logger.error("Error while transcoding svg file to an image", sre);
stream.close();
throw new ServletException("Error while transcoding svg file to an image");
} catch (TranscoderException te)
{
logger.error("Error while transcoding svg file to an image", te);
stream.close();
throw new ServletException("Error while transcoding svg file to an image");
}
} else
{
stream.write(svg.getBytes());
}

// prepare response
response.reset();
response.setContentLength(stream.size());
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment; filename=" + filename + "." + mime.name().toLowerCase());
response.setHeader("Content-type", mime.getType());
// set encoding before writing to out, check this
ServletOutputStream out = response.getOutputStream();
// Send content to Browser
out.write(stream.toByteArray());
out.flush();
}

public static final boolean isMultipartRequest(HttpServletRequest request)
{
// inspired by org.apache.commons.fileupload
logger.debug("content-type " + request.getContentType());
return REQUEST_METHOD_POST.equalsIgnoreCase(request.getMethod()) && request.getContentType() != null
&& request.getContentType().toLowerCase().startsWith(CONTENT_TYPE_MULTIPART);
}

private String getParameter(HttpServletRequest request, String name) throws IOException, ServletException
{

return request.getParameter(name);

}

private String getFilename(String name)
{
return (name != null) ? name : "chart";
}

private static Float getWidth(String width)
{
if (width != null && !width.isEmpty())
{
Float parsedWidth = Float.valueOf(width);
if (parsedWidth.compareTo(0.0F) > 0)
{
return parsedWidth;
}
}
return null;
}

private static MimeType getMime(String mime)
{
MimeType type = MimeType.get(mime);
if (type != null)
{
return type;
}
return MimeType.PNG;
}

protected void sendError(HttpServletRequest request, HttpServletResponse response, Throwable ex) throws IOException,
ServletException
{
String headers = null;
String htmlHeader =
"<HTML><HEAD><TITLE>Highcharts Export error</TITLE><style type=\"text/css\">"
+ "body {font-family: \"Trebuchet MS\", Arial, Helvetica, sans-serif;} table {border-collapse: collapse;}th {background-color:green;color:white;} td, th {border: 1px solid #98BF21;} </style></HEAD><BODY>";
String htmlFooter = "</BODY></HTML>";

response.setContentType("text/html");

PrintWriter out = response.getWriter();
Enumeration<String> e = request.getHeaderNames();
String svg = this.getParameter(request, "svg");

out.println(htmlHeader);
out.println("<h3>Error while converting SVG</h3>");
out.println("<h4>Error message</h4>");
out.println("<p>" + ex.getMessage() + "</p>");
out.println("<h4>Debug steps</h4><ol>"
+ "<li>Copy the SVG:<br/><textarea cols=100 rows=5>"
+ svg
+ "</textarea></li>"
+ "<li>Go to <a href='http://validator.w3.org/#validate_by_input' target='_blank'>validator.w3.org/#validate_by_input</a></li>"
+ "<li>Paste the SVG</li>" + "<li>Click More Options and select SVG 1.1 for Use Doctype</li>"
+ "<li>Click the Check button</li></ol>");

out.println("<h4>Request Headers</h4>");
out.println("<TABLE>");
out.println("<tr><th> Header </th><th> Value </th>");

while (e.hasMoreElements())
{
headers = (String) e.nextElement();
if (headers != null)
{
out.println("<tr><td align=center><b>" + headers + "</td>");
out.println("<td align=center>" + request.getHeader(headers) + "</td></tr>");
}
}
out.println("</TABLE><BR>");
out.println(htmlFooter);

}
}
<pre>

GreenPPS / SafePPS 阻止PPStream显示广告

PPStream里的广告越来越多。在看动漫的时候特别烦人。不想看广告但又想使用最新的PPS版本,所以就尝试了一下给PPS过滤广告。

  • 修改hosts文件:失败(PPS还是会把hosts改回原样),而且只能阻止有hostname的网址。
  •  阻止PPS缓存广告及其他宣传文件:成功

具体实现方法:

  • 找到PPS储存它下载广告的文件夹
  • 阻止PPS创建广告文件夹

这里感谢一下PPS的程序员。没有因为无法创建广告文件夹而限制PPS的播放功能。

下载链接:GreenPPS 1.3 Windows XP/Windows 7

http://code.google.com/p/safepps/

Lingoes灵格斯电子词典LD2(LDF)文件解析(附java词典导出程序)

新 Lingoes灵格斯电子词典LD2(LDF)文件单词提取器

http://code.google.com/p/lingoes-extractor/

下载

1. Windows版: http://lingoes-extractor.googlecode.com/files/lingoes-extractor-1.0.exe

2. Java版:http://lingoes-extractor.googlecode.com/files/lingoes-extractor-1.0.jar

程序演示

选择LD2文件跟导出文件:

导出后的文件:

 

 

 

支持已知所有Lingoes词典版本(2.x)。自动导出索引组(*.idx),所有词组(*.words),翻译(*.output)文件等。

Lingoes Reader / Exporter源程序下载https://dict4cn.googlecode.com/svn/trunk/importer/src/LingoesLd2Reader.java

源文件:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

/**
 * Lingoes LD2/LDF File Reader
 * 
 * <pre>
 * Lingoes Format overview:
 * 
 * General Information:
 * - Dictionary data are stored in deflate streams.
 * - Index group information is stored in an index array in the LD2 file itself.
 * - Numbers are using little endian byte order.
 * - Definitions and xml data have UTF-8 or UTF-16LE encodings.
 * 
 * LD2 file schema:
 * - File Header
 * - File Description
 * - Additional Information (optional)
 * - Index Group (corresponds to definitions in dictionary) 
 * - Deflated Dictionary Streams
 * -- Index Data
 * --- Offsets of definitions
 * --- Offsets of translations
 * --- Flags
 * --- References to other translations
 * -- Definitions
 * -- Translations (xml)
 * 
 * TODO: find encoding / language fields to replace auto-detect of encodings
 * 
 * </pre>
 * 
 * @author keke
 * 
 */
public class LingoesLd2Reader {
    private static final String[] AVAIL_ENCODINGS = { "UTF-8", "UTF-16LE", "UTF-16BE" };

    public static void main(String[] args) throws IOException {
        // download from
        // https://skydrive.live.com/?cid=a10100d37adc7ad3&sc=documents&id=A10100D37ADC7AD3%211172#cid=A10100D37ADC7AD3&sc=documents
        String ld2File = "X:\\kkdict\\dicts\\lingoes\\Prodic English-Vietnamese Business.ld2";

        // read lingoes ld2 into byte array
        ByteArrayOutputStream dataOut = new ByteArrayOutputStream();
        FileChannel fChannel = new RandomAccessFile(ld2File, "r").getChannel();
        fChannel.transferTo(0, fChannel.size(), Channels.newChannel(dataOut));
        fChannel.close();

        // as bytes
        ByteBuffer dataRawBytes = ByteBuffer.wrap(dataOut.toByteArray());
        dataRawBytes.order(ByteOrder.LITTLE_ENDIAN);

        System.out.println("文件:" + ld2File);
        System.out.println("类型:" + new String(dataRawBytes.array(), 0, 4, "ASCII"));
        System.out.println("版本:" + dataRawBytes.getShort(0x18) + "." + dataRawBytes.getShort(0x1A));
        System.out.println("ID: 0x" + Long.toHexString(dataRawBytes.getLong(0x1C)));

        int offsetData = dataRawBytes.getInt(0x5C) + 0x60;
        if (dataRawBytes.limit() > offsetData) {
            System.out.println("简介地址:0x" + Integer.toHexString(offsetData));
            int type = dataRawBytes.getInt(offsetData);
            System.out.println("简介类型:0x" + Integer.toHexString(type));
            int offsetWithInfo = dataRawBytes.getInt(offsetData + 4) + offsetData + 12;
            if (type == 3) {
                // without additional information
                readDictionary(ld2File, dataRawBytes, offsetData);
            } else if (dataRawBytes.limit() > offsetWithInfo - 0x1C) {
                readDictionary(ld2File, dataRawBytes, offsetWithInfo);
            } else {
                System.err.println("文件不包含字典数据。网上字典?");
            }
        } else {
            System.err.println("文件不包含字典数据。网上字典?");
        }
    }

    private static final long decompress(final String inflatedFile, final ByteBuffer data, final int offset,
            final int length, final boolean append) throws IOException {
        Inflater inflator = new Inflater();
        InflaterInputStream in = new InflaterInputStream(new ByteArrayInputStream(data.array(), offset, length),
                inflator, 1024 * 8);
        FileOutputStream out = new FileOutputStream(inflatedFile, append);
        writeInputStream(in, out);
        long bytesRead = inflator.getBytesRead();
        in.close();
        out.close();
        inflator.end();
        return bytesRead;
    }

    private static final String[] detectEncodings(final ByteBuffer inflatedBytes, final int offsetWords,
            final int offsetXml, final int defTotal, final int dataLen, final int[] idxData, final String[] defData)
            throws UnsupportedEncodingException {
        final int tests = Math.min(defTotal, 10);
        int defEnc = 0;
        int xmlEnc = 0;
        Pattern p = Pattern.compile("^.*[\\x00-\\x1f].*$");
        for (int i = 0; i < tests; i++) {
            readDefinitionData(inflatedBytes, offsetWords, offsetXml, dataLen, AVAIL_ENCODINGS[defEnc],
                    AVAIL_ENCODINGS[xmlEnc], idxData, defData, i);
            if (p.matcher(defData[0]).matches()) {
                if (defEnc < AVAIL_ENCODINGS.length - 1) {
                    defEnc++;
                }
                i = 0;
            }
            if (p.matcher(defData[1]).matches()) {
                if (xmlEnc < AVAIL_ENCODINGS.length - 1) {
                    xmlEnc++;
                }
                i = 0;
            }
        }
        System.out.println("词组编码:" + AVAIL_ENCODINGS[defEnc]);
        System.out.println("XML编码:" + AVAIL_ENCODINGS[xmlEnc]);
        return new String[] { AVAIL_ENCODINGS[defEnc], AVAIL_ENCODINGS[xmlEnc] };
    }

    private static final void extract(final String inflatedFile, final String indexFile,
            final String extractedWordsFile, final String extractedXmlFile, final String extractedOutputFile,
            final int[] idxArray, final int offsetDefs, final int offsetXml) throws IOException, FileNotFoundException,
            UnsupportedEncodingException {
        System.out.println("写入'" + extractedOutputFile + "'。。。");

        FileWriter indexWriter = new FileWriter(indexFile);
        FileWriter defsWriter = new FileWriter(extractedWordsFile);
        FileWriter xmlWriter = new FileWriter(extractedXmlFile);
        FileWriter outputWriter = new FileWriter(extractedOutputFile);
        // read inflated data
        ByteArrayOutputStream dataOut = new ByteArrayOutputStream();
        FileChannel fChannel = new RandomAccessFile(inflatedFile, "r").getChannel();
        fChannel.transferTo(0, fChannel.size(), Channels.newChannel(dataOut));
        fChannel.close();
        ByteBuffer dataRawBytes = ByteBuffer.wrap(dataOut.toByteArray());
        dataRawBytes.order(ByteOrder.LITTLE_ENDIAN);

        final int dataLen = 10;
        final int defTotal = offsetDefs / dataLen - 1;

        String[] words = new String[defTotal];
        int[] idxData = new int[6];
        String[] defData = new String[2];

        final String[] encodings = detectEncodings(dataRawBytes, offsetDefs, offsetXml, defTotal, dataLen, idxData,
                defData);

        dataRawBytes.position(8);
        int counter = 0;
        final String defEncoding = encodings[0];
        final String xmlEncoding = encodings[1];
        for (int i = 0; i < defTotal; i++) {
            readDefinitionData(dataRawBytes, offsetDefs, offsetXml, dataLen, defEncoding, xmlEncoding, idxData,
                    defData, i);

            words[i] = defData[0];
            defsWriter.write(defData[0]);
            defsWriter.write("\n");

            xmlWriter.write(defData[1]);
            xmlWriter.write("\n");

            outputWriter.write(defData[0]);
            outputWriter.write("=");
            outputWriter.write(defData[1]);
            outputWriter.write("\n");

            System.out.println(defData[0] + " = " + defData[1]);
            counter++;
        }

        for (int i = 0; i < idxArray.length; i++) {
            int idx = idxArray[i];
            indexWriter.write(words[idx]);
            indexWriter.write(", ");
            indexWriter.write(String.valueOf(idx));
            indexWriter.write("\n");
        }
        indexWriter.close();
        defsWriter.close();
        xmlWriter.close();
        outputWriter.close();
        System.out.println("成功读出" + counter + "组数据。");
    }

    private static final void getIdxData(final ByteBuffer dataRawBytes, final int position, final int[] wordIdxData) {
        dataRawBytes.position(position);
        wordIdxData[0] = dataRawBytes.getInt();
        wordIdxData[1] = dataRawBytes.getInt();
        wordIdxData[2] = dataRawBytes.get() & 0xff;
        wordIdxData[3] = dataRawBytes.get() & 0xff;
        wordIdxData[4] = dataRawBytes.getInt();
        wordIdxData[5] = dataRawBytes.getInt();
    }

    private static final void inflate(final ByteBuffer dataRawBytes, final List<Integer> deflateStreams,
            final String inflatedFile) {
        System.out.println("解压缩'" + deflateStreams.size() + "'个数据流至'" + inflatedFile + "'。。。");
        int startOffset = dataRawBytes.position();
        int offset = -1;
        int lastOffset = startOffset;
        boolean append = false;
        try {
            for (Integer offsetRelative : deflateStreams) {
                offset = startOffset + offsetRelative.intValue();
                decompress(inflatedFile, dataRawBytes, lastOffset, offset - lastOffset, append);
                append = true;
                lastOffset = offset;
            }
        } catch (Throwable e) {
            System.err.println("解压缩失败: 0x" + Integer.toHexString(offset) + ": " + e.toString());
        }
    }

    private static final void readDefinitionData(final ByteBuffer inflatedBytes, final int offsetWords,
            final int offsetXml, final int dataLen, final String wordEncoding, final String xmlEncoding,
            final int[] idxData, final String[] defData, final int i) throws UnsupportedEncodingException {
        getIdxData(inflatedBytes, dataLen * i, idxData);
        int lastWordPos = idxData[0];
        int lastXmlPos = idxData[1];
        final int flags = idxData[2];
        int refs = idxData[3];
        int currentWordOffset = idxData[4];
        int currenXmlOffset = idxData[5];
        String xml = strip(new String(inflatedBytes.array(), offsetXml + lastXmlPos, currenXmlOffset - lastXmlPos,
                xmlEncoding));
        while (refs-- > 0) {
            int ref = inflatedBytes.getInt(offsetWords + lastWordPos);
            getIdxData(inflatedBytes, dataLen * ref, idxData);
            lastXmlPos = idxData[1];
            currenXmlOffset = idxData[5];
            if (xml.isEmpty()) {
                xml = strip(new String(inflatedBytes.array(), offsetXml + lastXmlPos, currenXmlOffset - lastXmlPos,
                        xmlEncoding));
            } else {
                xml = strip(new String(inflatedBytes.array(), offsetXml + lastXmlPos, currenXmlOffset - lastXmlPos,
                        xmlEncoding)) + ", " + xml;
            }
            lastWordPos += 4;
        }
        defData[1] = xml;

        String word = new String(inflatedBytes.array(), offsetWords + lastWordPos, currentWordOffset - lastWordPos,
                wordEncoding);
        defData[0] = word;
    }

    private static final void readDictionary(final String ld2File, final ByteBuffer dataRawBytes,
            final int offsetWithIndex) throws IOException, FileNotFoundException, UnsupportedEncodingException {
        System.out.println("词典类型:0x" + Integer.toHexString(dataRawBytes.getInt(offsetWithIndex)));
        int limit = dataRawBytes.getInt(offsetWithIndex + 4) + offsetWithIndex + 8;
        int offsetIndex = offsetWithIndex + 0x1C;
        int offsetCompressedDataHeader = dataRawBytes.getInt(offsetWithIndex + 8) + offsetIndex;
        int inflatedWordsIndexLength = dataRawBytes.getInt(offsetWithIndex + 12);
        int inflatedWordsLength = dataRawBytes.getInt(offsetWithIndex + 16);
        int inflatedXmlLength = dataRawBytes.getInt(offsetWithIndex + 20);
        int definitions = (offsetCompressedDataHeader - offsetIndex) / 4;
        List<Integer> deflateStreams = new ArrayList<Integer>();
        dataRawBytes.position(offsetCompressedDataHeader + 8);
        int offset = dataRawBytes.getInt();
        while (offset + dataRawBytes.position() < limit) {
            offset = dataRawBytes.getInt();
            deflateStreams.add(Integer.valueOf(offset));
        }
        int offsetCompressedData = dataRawBytes.position();
        System.out.println("索引词组数目:" + definitions);
        System.out.println("索引地址/大小:0x" + Integer.toHexString(offsetIndex) + " / "
                + (offsetCompressedDataHeader - offsetIndex) + " B");
        System.out.println("压缩数据地址/大小:0x" + Integer.toHexString(offsetCompressedData) + " / "
                + (limit - offsetCompressedData) + " B");
        System.out.println("词组索引地址/大小(解压缩后):0x0 / " + inflatedWordsIndexLength + " B");
        System.out.println("词组地址/大小(解压缩后):0x" + Integer.toHexString(inflatedWordsIndexLength) + " / "
                + inflatedWordsLength + " B");
        System.out.println("XML地址/大小(解压缩后):0x" + Integer.toHexString(inflatedWordsIndexLength + inflatedWordsLength)
                + " / " + inflatedXmlLength + " B");
        System.out.println("文件大小(解压缩后):" + (inflatedWordsIndexLength + inflatedWordsLength + inflatedXmlLength) / 1024
                + " KB");
        String inflatedFile = ld2File + ".inflated";
        inflate(dataRawBytes, deflateStreams, inflatedFile);

        if (new File(inflatedFile).isFile()) {
            String indexFile = ld2File + ".idx";
            String extractedFile = ld2File + ".words";
            String extractedXmlFile = ld2File + ".xml";
            String extractedOutputFile = ld2File + ".output";

            dataRawBytes.position(offsetIndex);
            int[] idxArray = new int[definitions];
            for (int i = 0; i < definitions; i++) {
                idxArray[i] = dataRawBytes.getInt();
            }
            extract(inflatedFile, indexFile, extractedFile, extractedXmlFile, extractedOutputFile, idxArray,
                    inflatedWordsIndexLength, inflatedWordsIndexLength + inflatedWordsLength);
        }
    }

    private static final String strip(final String xml) {
        int open = 0;
        int end = 0;
        if ((open = xml.indexOf("<![CDATA[")) != -1) {
            if ((end = xml.indexOf("]]>", open)) != -1) {
                return xml.substring(open + "<![CDATA[".length(), end).replace('\t', ' ').replace('\n', ' ')
                        .replace('\u001e', ' ').replace('\u001f', ' ');
            }
        } else if ((open = xml.indexOf("<Ô")) != -1) {
            if ((end = xml.indexOf("</Ô", open)) != -1) {
                open = xml.indexOf(">", open + 1);
                return xml.substring(open + 1, end).replace('\t', ' ').replace('\n', ' ').replace('\u001e', ' ')
                        .replace('\u001f', ' ');
            }
        } else {
            StringBuilder sb = new StringBuilder();
            end = 0;
            open = xml.indexOf('<');
            do {
                if (open - end > 1) {
                    sb.append(xml.substring(end + 1, open));
                }
                open = xml.indexOf('<', open + 1);
                end = xml.indexOf('>', end + 1);
            } while (open != -1 && end != -1);
            return sb.toString().replace('\t', ' ').replace('\n', ' ').replace('\u001e', ' ').replace('\u001f', ' ');
        }
        return "";
    }

    private static final void writeInputStream(final InputStream in, final OutputStream out) throws IOException {
        byte[] buffer = new byte[1024 * 8];
        int len;
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }

}

PPS无广告启动器

PPS无广告启动器

记录时间:2011-03-16

安装过程

  1. 正常安装PPStream
  2. 下载GreenPPS并解压缩到随意一个文件夹里
  3. 双击pps_noads_launcher

启动器原理

去除广告方法

去除PPS广告可采用不同的方法

  • 使用专门的DNS屏蔽广告网站
    • 例如使用dnsmasq网络名服务器软件
  • 修改hosts文件屏蔽广告网站
    • PPS会自动修改hosts文件。使用这个方法必须用360或者其他软件保护hosts文件,免遭它被PPS修改。
  • 使用Proxy屏蔽广告网站
    • 例如使用Apache Proxy+Rewrite或者Fiddler2 Rules
  • 修改PPS主程序
    • 例如跳过广告部分,去除Flash支持,模拟高级会员
    • 网上有个别绿色PPS版本下载。缺点是不能更新而且需要考虑安全性方面的问题。
  • 删除并锁定PPS广告文件夹。
    • 例如GreenPPS。
GreenPPS

GreenPPS的原理很简单。它本身只是由两行Batch脚本所组成:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

REM == delete all pps ads directories ==
RMDIR /s /q "%APPDATA%\PPStream\banner"
ECHO banner >> "%APPDATA%\PPStream\banner"
RMDIR /s /q "%APPDATA%\PPStream\adsys"
ECHO adsys >> "%APPDATA%\PPStream\adsys"

REM == detect ppstream director ==
SET pps_dirs="%ProgramFiles%",C:\PPS.tv,D:\PPS.tv

FOR %%A IN (%pps_dirs%) DO (
  SET pps_cmd="%%~A\PPStream\PPStream.exe"
  IF EXIST "!pps_cmd!" (
    START "PPStream" /MAX /WAIT "!pps_cmd!" >> %APPDATA%\PPStream\adsys
    GOTO end
  )
)

:end

ENDLOCAL 
PAUSE
  1. 删除PPS广告文件夹
  2. 启动并PPS并锁定广告文件夹
运行先提条件

主要运行条件是PPS程序在不能创建广告文件夹的情况下仍可正常运行。(PPS到最新的版本为止都可以正常运行。)