src/org/nutz/mvc/upload/util/RingItem.java
int mark(byte[] bs, int[] fails) {
        if (!isLoaded)
            throw new MarkUnloadedRingItemException();

        byte start = bs[0];

        for (; r < max; r++) {
            // 可能是边界，开始匹配
            if (buffer[r] == start) {
                int re = 0; // 已经匹配长度
                int j = r; // 在内容值字节数组中的指针
                while (true) {
                    re++;
                    j++;
                    // 全部匹配
                    if (re == bs.length) {
                        nextmark = j;
                        return -1;
                    }
                    // 到达本项目的结尾，但是并不确定是否是边界，因为还未匹配完
                    // 因此暂时假设这个不会被匹配
                    if (j == max) {
                        nextmark = max;
                        if (isStreamEnd) {
                            r = max;
                            return 0;
                        }
                        return re;
                    }
                    // 如果字符不相等，那么查看一下回退数组
                    // 如果回退到 0，则退出循环，因为这不是边界，否则继续循环匹配边界
                    if (bs[re] != buffer[j]) {
                        re = fails[re];
                        // 再次判断回退后位置，如果还是不相同，则退出循环
                        if (bs[re] != buffer[j]) {
                            break;
                        }
                        // 如果已经回退到了 0，你这么右边界置为 j，表示从头搜索
                        else if (re == 0) {
                            r = j;
                        }
                        // 否则扩大边界，并继续循环
                        else {
                            r += re == 0 ? 1 : re;
                        }

                    }
                }
                // make 'r' jump to 'j'
                r = j;
            }
        }
        // Fail to found
        nextmark = max;
        return 0;
    }
int mark(byte[] bs, int[] fails) {
        if (!isLoaded)
            throw new MarkUnloadedRingItemException();

        byte start = bs[0];

        for (; r < max; r++) {
            // 可能是边界，开始匹配
            if (buffer[r] == start) {
                int re = 0; // 已经匹配长度
                int j = r; // 在内容值字节数组中的指针
                while (true) {
                    re++;
                    j++;
                    // 全部匹配
                    if (re == bs.length) {
                        nextmark = j;
                        return -1;
                    }
                    // 到达本项目的结尾，但是并不确定是否是边界，因为还未匹配完
                    // 因此暂时假设这个不会被匹配
                    if (j == max) {
                        nextmark = max;
                        if (isStreamEnd) {
                            r = max;
                            return 0;
                        }
                        return re;
                    }
                    // 如果字符不相等，那么查看一下回退数组
                    // 如果回退到 0，则退出循环，因为这不是边界，否则继续循环匹配边界
                    if (bs[re] != buffer[j]) {
                        re = fails[re];
                        // 再次判断回退后位置，如果还是不相同，则退出循环
                        if (bs[re] != buffer[j]) {
                            break;
                        }
                        // 如果已经回退到了 0，你这么右边界置为 j，表示从头搜索
                        else if (re == 0) {
                            r = j;
                        }
                        // 否则扩大边界，并继续循环
                        else {
                            r += re == 0 ? 1 : re;
                        }

                    }
                }
                // make 'r' jump to 'j'
                r = j;
            }
        }
        // Fail to found
        nextmark = max;
        return 0;
    }
从给定 offs 尽力匹配给出的数组。
<p>
需要注意的是，如果返回的是 >0 的数，内部的标志位将被设置到第一个匹配字符，以便 DUMP 内容。 <br>
所以，如果下一个节点给出的结论是 -1，但是 'l' 并不是0，那么说明这个匹配是失败的，需要将 本节点的 r 置到 max 处。
<p>
返回值
<ul>
<li><b>-1</b> - 全部被匹配
<li><b>0</b> - 未发现匹配
<li><b>大于 0</b> - 在缓冲的末尾发现匹配，但是没有匹配全，希望下一个节点继续从这个位置匹配
</ul>

@param bs
数组
@return -1, 0 或者 +n