/* * Copyright 2013 Jive Software, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.jivesoftware.os.amza.api.filer; import com.google.common.math.IntMath; import java.io.IOException; /** * All of the methods are intentionally left unsynchronized. Up to caller to do the right thing using the Object returned by lock() */ public class HeapFiler implements IFiler { private byte[] bytes = new byte[0]; private long fp = 0; private long maxLength = 0; public HeapFiler() { } public HeapFiler(int size) { bytes = new byte[size]; maxLength = 0; } private HeapFiler(byte[] _bytes, int _maxLength) { bytes = _bytes; maxLength = _maxLength; } public static HeapFiler fromBytes(byte[] _bytes, int length) { return new HeapFiler(_bytes, length); } public HeapFiler createReadOnlyClone() { HeapFiler heapFiler = new HeapFiler(); heapFiler.bytes = bytes; heapFiler.maxLength = maxLength; return heapFiler; } public byte[] getBytes() { if (maxLength == bytes.length) { return bytes; } else { return trim(bytes, (int) maxLength); } } public byte[] copyUsedBytes() { return trim(bytes, (int) maxLength); } public byte[] leakBytes() { return bytes; } public void reset() { fp = 0; maxLength = 0; } public void reset(int _maxLength) { fp = 0; maxLength = _maxLength; } @Override public Object lock() { return this; } @Override public int read() throws IOException { if (fp + 1 > maxLength) { return -1; } int b = bytes[(int) fp] & 0xFF; fp++; return b; } @Override public int read(byte[] b) throws IOException { return read(b, 0, b.length); } @Override public int read(byte b[], int _offset, int _len) throws IOException { if (fp > maxLength) { return -1; } int len = _len; if (fp + len > maxLength) { len = (int) (maxLength - fp); } try { System.arraycopy(bytes, (int) fp, b, _offset, len); } catch (Exception x) { System.out.println("Error:" + bytes.length + " srcPos:" + fp + " " + b.length + " dstPos:" + _offset + " legnth:" + len); throw x; } fp += len; return len; } @Override public void write(byte b) throws IOException { if (fp + 1 > bytes.length) { bytes = grow(bytes, Math.max((int) ((fp + 1) - bytes.length), bytes.length)); } bytes[(int)fp] = b; fp += 1; maxLength = Math.max(maxLength, fp); } @Override public void write(byte _b[], int _offset, int _len) throws IOException { if (_b == null) { return; } if (fp + _len > bytes.length) { bytes = grow(bytes, Math.max((int) ((fp + _len) - bytes.length), bytes.length)); } System.arraycopy(_b, _offset, bytes, (int) fp, _len); fp += _len; maxLength = Math.max(maxLength, fp); } @Override public long getFilePointer() throws IOException { return fp; } @Override public void seek(long _position) throws IOException { fp = _position; maxLength = Math.max(maxLength, fp); } @Override public long skip(long _position) throws IOException { fp += _position; maxLength = Math.max(maxLength, fp); return fp; } @Override public void setLength(long len) throws IOException { if (len < 0) { throw new IOException(); } byte[] newBytes = new byte[(int) len]; System.arraycopy(bytes, 0, newBytes, 0, Math.min(bytes.length, newBytes.length)); fp = (int) len; bytes = newBytes; maxLength = len; } @Override public long length() throws IOException { return maxLength; } @Override public void eof() throws IOException { bytes = trim(bytes, (int) fp); maxLength = fp; } @Override public void close() throws IOException { } @Override public void flush(boolean fsync) throws IOException { } private static byte[] trim(byte[] src, int count) { byte[] newSrc = new byte[count]; System.arraycopy(src, 0, newSrc, 0, count); return newSrc; } static final public byte[] grow(byte[] src, int amount) { if (amount < 0) { throw new IllegalArgumentException("amount must be greater than zero"); } if (src == null) { return new byte[amount]; } byte[] newSrc = new byte[IntMath.checkedAdd(src.length, amount)]; System.arraycopy(src, 0, newSrc, 0, src.length); return newSrc; } }