⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 packethelper.java

📁 MilyQQ是一个使用控制台的QQ客户端,基于LumaQQ的核心JQL包开发,只有一个可执行的jar包(MilyQQ.jar),携带方便,由于是Java程序,因此理论上应该可以运行于所有平台,不过基于
💻 JAVA
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 notXX
*                    luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU 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
*/
//package edu.tsinghua.lumaqq.qq.packets;

import java.nio.ByteBuffer;

//import edu.tsinghua.lumaqq.qq.beans.QQUser;

//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;

/**
 * @author notXX
 * @author luma
 */
public final class PacketHelper {
    // Log对象
//    static Log log = LogFactory.getLog(PacketHelper.class);
    // 当前使用的parser
    private IParser parser;

    private static final int PARSER_COUNT = 2;
    private IParser[] parsers;
    private PacketHistory history;

    public PacketHelper() {
    	history = new PacketHistory();
    	parsers = new IParser[] {
    		new BasicParser(history),
    		new _05Parser()
        };
    }

	/**
	 * 把ByteBuffer中的内容解析成一个InPacket子类,从buf的当前位置开始解析,直到limit为止
	 * 不论解析成功或者失败,要把buf的position置于length后
	 *
	 * @param buf
	 * 				ByteBuffer对象
	 * @param debug
	 * @return InPacket
	 * 		如果解析失败,或者缓冲区中的内容构不成一个包,返回null
	 * @throws PacketParseException
	 * 					如果包格式不对
	 */
	public InPacket processIn(ByteBuffer buf, QQUser user, boolean debug) throws PacketParseException {
		if(!findParser(buf))
			return null;
    	return processIn(buf, parser.getLength(), user, debug);
	}

	/**
	 * 查找一个能解析buf中内容的parser
	 *
	 * @param buf
	 * 		ByteBuffer
	 * @return
	 * 		true表示找到,false表示没有找到
	 */
	private boolean findParser(ByteBuffer buf) {
    	if(parser == null) {
    		for(int i = 0; i < PARSER_COUNT; i++) {
    			if(parsers[i].accept(buf)) {
    				parser = parsers[i];
    				break;
    			}
    		}
    	}
    	return parser != null;
	}

	/**
	 * 把ByteBuffer中的内容解析成一个InPacket子类,从buf的当前位置开始解析length字节
	 * 不论解析成功或者失败,buf的position将位于length后
	 *
	 * @param buf
	 * 				ByteBuffer对象
	 * @param type
	 * 				包类型
	 * @param length
	 * 				包长度
	 * @param debug
	 * @return InPacket
	 * @throws PacketParseException
	 * 					如果包格式不对
	 */
	public InPacket processIn(ByteBuffer buf, int length, QQUser user, boolean debug) throws PacketParseException {
		if(!findParser(buf))
			return null;
	    // 保存当前位置
	    int offset = buf.position();
	    // 检查重复性
	    boolean duplicated = parser.isDuplicated(buf);
	    boolean needReply = parser.isDuplicatedNeedReply();
	    if(duplicated && !needReply && !debug) {
	        buf.position(offset + length);
	        parser = null;
	        return null;
	    }

	    // 解析包
        try {
            InPacket ret = parser.parseIncoming(buf, length, user);
	        ret.setDuplicated(duplicated);
	        return ret;
        } catch (PacketParseException e) {
            throw e;
        } finally {
	        buf.position(offset + length);
	        parser = null;
        }
	}

	/**
	 * 把buf中的数据解析为一个Packet子类,方法自动判断是InPacket还是OutPacket
	 * <p>
	 * 只有Debugger需要访问此方法,此方法依赖于isIncoming方法,这个有个问题,有些
	 * 协议族的输入包和输出包无法分辩,以后要改正这个问题
	 * </p>
	 *
	 * @param buf
	 * @return
	 * @throws PacketParseException
	 */
	public Packet process(ByteBuffer buf, QQUser user, boolean debug) throws PacketParseException {
		if(!findParser(buf))
			return null;

		if(parser.isIncoming(buf))
			return processIn(buf, user, debug);
		else
			return processOut(buf, user);
	}

	/**
	 * 把ByteBuffer中的内容解析成一个InPacket子类,从buf的当前位置开始解析,直到limit为止
	 * 不论解析成功或者失败,要把buf的position置于length后
	 *
	 * @param buf
	 * @param type
	 * @return
	 * @throws PacketParseException
	 */
	public OutPacket processOut(ByteBuffer buf, QQUser user) throws PacketParseException {
		if(!findParser(buf))
			return null;
	    return processOut(buf, parser.getLength(), user);
	}

    /**
	 * 把ByteBuffer中的内容解析成一个InPacket子类,从buf的当前位置开始解析,直到limit为止
	 * 不论解析成功或者失败,要把buf的position置于length后
	 *
     * @param buf
     * @param length
     * @param debug
     * @return
     * @throws PacketParseException
     */
    private OutPacket processOut(ByteBuffer buf, int length, QQUser user) throws PacketParseException {
		if(!findParser(buf))
			return null;

        int pos = buf.position();
	    try {
            OutPacket ret = parser.parseOutcoming(buf, length, user);
            return ret;
        } catch (PacketParseException e) {
            throw e;
        } finally {
            buf.position(pos + length);
            parser = null;
        }
    }

	/**
	 * @return Returns the history.
	 */
	public PacketHistory getHistory() {
		return history;
	}

	/**
	 * 把position设置到下一个包的起始位置处。一般当某段数据没有parser
	 * 可以时,调用此方法跳过这段数据
	 *
	 * @param buf
	 * @return
	 * 		true表示重定位成功,false表示失败或者推迟重定位
	 */
	public boolean relocate(ByteBuffer buf) {
		int offset = buf.position();
		for(int i = 0; i < PARSER_COUNT; i++) {
			int relocated = parsers[i].relocate(buf);
			if(relocated > offset) {
				buf.position(relocated);
				return true;
			}
		}
		return false;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -