/******************************************************************************* * Copyright (C) 2013 JMaNGOS <http://jmangos.org/> * * 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, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.jmangos.commons.network.model; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import javolution.text.TextBuilder; import org.jboss.netty.channel.Channel; /** * The Class ReceivablePacket. * * @author MinimaJack */ public abstract class ReceivablePacket extends AbstractPacket implements Runnable, Cloneable { private final CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); /** * Instantiates a new receivable packet. */ protected ReceivablePacket() { } /** * Instantiates a new receivable packet. * * @param opcode * the opcode */ protected ReceivablePacket(final int opcode) { setOpCode(opcode); } /** The _client. */ protected NetworkChannel _client; /** * Sets the client. * * @param client * the new client */ public final void setClient(final NetworkChannel client) { this._client = client; } /** * Gets the client. * * @return the client */ public NetworkChannel getClient() { return this._client; } /** * Gets the channel. * * @return the channel */ public final Channel getChannel() { return this._client.getChannel(); } /** * Should be overridden. * * @return the minimum length */ public int getMinimumLength() { return 0; } /** * Gets the avaliable bytes. * * @return the avaliable bytes */ public final int getAvaliableBytes() { return getByteBuffer().readableBytes(); } /** * Read. * * @return true, if successful * @throws BufferUnderflowException * the buffer underflow exception * @throws RuntimeException * the runtime exception */ public boolean read() throws BufferUnderflowException, RuntimeException { readImpl(); runImpl(); return true; } /** * Read impl. * * @throws BufferUnderflowException * the buffer underflow exception * @throws RuntimeException * the runtime exception */ protected abstract void readImpl() throws BufferUnderflowException, RuntimeException; /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public final void run() { runImpl(); } /** * Run impl. */ protected abstract void runImpl(); /** * Skip. * * @param bytes * the bytes */ protected final void skip(final int bytes) { if (getByteBuffer().readableBytes() < bytes) { throw new BufferUnderflowException(); } getByteBuffer().skipBytes(bytes); } /** * Skip all. */ protected final void skipAll() { skip(getByteBuffer().readableBytes()); } /** * Read b. * * @param len * the len * @return the byte[] */ protected final byte[] readB(final int len) { final byte[] tmp = new byte[len]; getByteBuffer().readBytes(tmp); return tmp; } /** * Read b. * * @param dst * the dst * @param offset * the offset * @param len * the len */ protected final void readB(final byte[] dst, final int offset, final int len) { getByteBuffer().readBytes(dst, offset, len); } /** * Read c. * * @return the int */ protected final int readC() { return getByteBuffer().readByte() & 0xFF; } /** * Read h. * * @return the int */ protected final int readH() { return getByteBuffer().readShort(); } /** * Read d. * * @return the int */ protected final int readD() { return getByteBuffer().readInt(); } /** * Read q. * * @return the long */ protected final long readQ() { return getByteBuffer().readLong(); } /** * Read f. * * @return the float */ protected final float readF() { return getByteBuffer().readFloat(); } /** * Read s. * * @return the string */ protected final String readS() { final TextBuilder tb = TextBuilder.newInstance(); for (byte c; (c = getByteBuffer().readByte()) != 0;) { tb.append((char) c); } final String str = tb.toString(); TextBuilder.recycle(tb); return str; } /** * Read s. * * @return the string */ protected final String readUTF8(final int maxLength) { String string = null; final byte[] tsring = new byte[maxLength]; int i = 0; while (i < maxLength) { tsring[i] = (byte) readC(); if (tsring[i] == 0) { break; } i++; } try { string = this.decoder.decode(ByteBuffer.wrap(tsring, 0, i)).toString(); } catch (final CharacterCodingException e) { e.printStackTrace(); } return string; } /** * Read packed guid. * * @param guid * the guid (uint64) */ protected final Long readPackedGuid() { long guid = 0L; final int mask = readC(); if (mask == 0) { return guid; } int i = 0; while (i < 8) { if ((mask & (1 << i)) != 0) { final long val = readC(); guid |= (val << (i * 8)); } i++; } return guid; } /** * Clone packet. * * @return the receivable packet */ public ReceivablePacket clonePacket() { try { return (ReceivablePacket) super.clone(); } catch (final CloneNotSupportedException e) { return null; } } }