/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.nio; import java.nio.ByteBuffer; import com.ttProject.nio.channels.IReadChannel; /** * buffer for access data. * @author taktod */ public class CacheBuffer { /** buffer */ private ByteBuffer buffer = null; /** target channel */ private IReadChannel targetChannel; /** position for process */ private int position; /** remain data for channel */ private int remaining; /** * constructor * @param source * @throws Exception */ public CacheBuffer(IReadChannel source) throws Exception { this(source, source.size() - source.position()); } /** * constructor * @param source * @param size * @throws Exception */ public CacheBuffer(IReadChannel source, int size) throws Exception { this.targetChannel = source; this.position = source.position(); this.remaining = size; } /** * get byte * @return * @throws Exception */ public byte get() throws Exception { resetData(1); return buffer.get(); } /** * get short * @return * @throws Exception */ public short getShort() throws Exception { resetData(2); return buffer.getShort(); } /** * get long * @return * @throws Exception */ public long getLong() throws Exception { resetData(8); return buffer.getLong(); } /** * get int * @return * @throws Exception */ public int getInt() throws Exception { resetData(4); return buffer.getInt(); } /** * get midium (read 3byte integer) * @return * @throws Exception */ public int getMidiumInt() throws Exception { resetData(3); return (buffer.get() << 16) + buffer.getShort(); } /** * get buffer data for anysize. * @param size * @return * @throws Exception */ public ByteBuffer getBuffer(int size) throws Exception { resetData(size); byte[] data = new byte[size]; buffer.get(data); return ByteBuffer.wrap(data); } /** * if cache is short, get more cache. * @throws Exception */ private void resetData(int bytesLoad) throws Exception { // check the cache size if(buffer == null || buffer.remaining() < bytesLoad) { // check the remain data size if(remaining == 0 && buffer.remaining() == 0) { throw new Exception("eof already"); } int bufRemain; if(buffer == null) { bufRemain = 0; } else { bufRemain = buffer.remaining(); } // load data int bufSize = (16777216 > remaining) ? remaining : 16777216; ByteBuffer buf = ByteBuffer.allocate(bufSize); targetChannel.position(position); targetChannel.read(buf); buf.flip(); // update information. position += buf.remaining(); remaining -= buf.remaining(); // update buffer data. ByteBuffer buf2 = ByteBuffer.allocate(buf.remaining() + bufRemain); if(bufRemain != 0) { buf2.put(buffer); } buf2.put(buf); buf2.flip(); buffer = buf2; } if(buffer.remaining() < bytesLoad) { throw new Exception("data is too short."); } } /** * size of remaining * @return */ public int remaining() { if(buffer == null) { return remaining; } return remaining + buffer.remaining(); } /** * position * @return */ public int position() { return position - buffer.remaining(); } }