ChainedBuffer - corrected issues related to buffer obfuscation and use

of source data buffer
This commit is contained in:
ghidra1 2019-05-28 15:16:52 -04:00
parent ff273eeeda
commit 8495cc68ee
5 changed files with 294 additions and 109 deletions

View file

@ -132,8 +132,8 @@ public class ChainedBuffer implements Buffer {
this.useXORMask = enableObfuscation;
if (size < 0) {
throw new IllegalArgumentException("Maximum bufer size is " + Integer.MAX_VALUE +
"; given size of " + size);
throw new IllegalArgumentException(
"Maximum bufer size is " + Integer.MAX_VALUE + "; given size of " + size);
}
if (uninitializedDataSource != null) {
@ -588,9 +588,8 @@ public class ChainedBuffer implements Buffer {
// Create new DBBuffer
int cnt = size - offset;
ChainedBuffer newDBBuf =
new ChainedBuffer(cnt, useXORMask, uninitializedDataSource,
uninitializedDataSourceOffset + offset, bufferMgr);
ChainedBuffer newDBBuf = new ChainedBuffer(cnt, useXORMask, uninitializedDataSource,
uninitializedDataSourceOffset + offset, bufferMgr);
// Copy data from this DBBuffer into new DBBuffer
int newOffset = 0;
@ -879,7 +878,7 @@ public class ChainedBuffer implements Buffer {
int id = dataBufferIdTable[index];
if (id < 0) {
if (uninitializedDataSource != null) {
uninitializedDataSource.get(offset, data, uninitializedDataSourceOffset +
uninitializedDataSource.get(uninitializedDataSourceOffset + offset, data,
dataOffset, len);
}
else {
@ -957,7 +956,7 @@ public class ChainedBuffer implements Buffer {
int id = dataBufferIdTable[index];
if (id < 0) {
if (uninitializedDataSource != null) {
return uninitializedDataSource.getByte(uninitializedDataSourceOffset + bufferDataOffset);
return uninitializedDataSource.getByte(uninitializedDataSourceOffset + offset);
}
return 0;
}
@ -1081,7 +1080,8 @@ public class ChainedBuffer implements Buffer {
* @param endOffset ending offset, exclusive
* @param fillByte byte value
*/
public synchronized void fill(int startOffset, int endOffset, byte fillByte) throws IOException {
public synchronized void fill(int startOffset, int endOffset, byte fillByte)
throws IOException {
if (readOnly)
throw new UnsupportedOperationException("Read-only buffer");
if (endOffset <= startOffset)
@ -1372,28 +1372,28 @@ public class ChainedBuffer implements Buffer {
* @param buf newly allocated database buffer
* @throws IOException
*/
private void initializeAllocatedBuffer(int chainBufferIndex, DataBuffer buf) throws IOException {
if (uninitializedDataSource != null) {
int offset = chainBufferIndex * dataSpace;
int len = size - offset;
if (len >= dataSpace) {
len = dataSpace;
}
else {
buf.clear(); // partial fill - clear entire buffer first
}
byte[] data = new byte[len];
uninitializedDataSource.get(uninitializedDataSourceOffset + offset, data, 0, len);
if (useXORMask) {
for (int i = 0; i < len; i++) {
data[i] = xorMaskByte(i, data[i]);
}
}
buf.put(dataBaseOffset, data);
private void initializeAllocatedBuffer(int chainBufferIndex, DataBuffer buf)
throws IOException {
int offset = chainBufferIndex * dataSpace;
int len = size - offset;
if (len >= dataSpace) {
len = dataSpace;
}
else {
buf.clear();
buf.clear(); // partial fill - clear entire buffer first
}
byte[] data = new byte[len];
if (uninitializedDataSource != null) {
uninitializedDataSource.get(uninitializedDataSourceOffset + offset, data, 0, len);
}
if (useXORMask) {
for (int i = 0; i < len; i++) {
data[i] = xorMaskByte(i, data[i]);
}
}
buf.put(dataBaseOffset, data);
}
/**

View file

@ -15,8 +15,7 @@
*/
package db;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Arrays;
@ -39,19 +38,22 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
private static final Random random = new Random(1);
private final boolean obfuscated;
private final Buffer sourceData;
private final int sourceDataOffset;
/**
* Constructor for DatabaseTest.
* @param arg0
*/
AbstractChainedBufferTest(boolean obfuscated) {
AbstractChainedBufferTest(boolean obfuscated, Buffer sourceData, int sourceDataOffset) {
super();
this.obfuscated = obfuscated;
this.sourceData = sourceData;
this.sourceDataOffset = sourceDataOffset;
}
@Before
public void setUp() throws Exception {
mgr = new BufferMgr(BUFFER_SIZE, CACHE_SIZE, BufferMgr.DEFAULT_CHECKPOINT_COUNT);
}
@ -63,15 +65,26 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
@Test
public void testCreateChainedBuffer() throws IOException {
ChainedBuffer cb = new ChainedBuffer(128 * 1024, obfuscated, mgr);
byte[] origBytes = new byte[128 * 1024];
Arrays.fill(origBytes, (byte) '1');
assertEquals(origBytes.length, cb.put(0, origBytes));
ChainedBuffer cb =
new ChainedBuffer(128 * 1024, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] origBytes = new byte[cb.length()];
if (sourceData != null) {
sourceData.get(sourceDataOffset, origBytes);
}
assertArrayEquals(origBytes, cb.get(0, origBytes.length));
cb = new ChainedBuffer(BUFFER_SIZE / 2, obfuscated, sourceData, sourceDataOffset, mgr);
origBytes = new byte[cb.length()];
if (sourceData != null) {
sourceData.get(sourceDataOffset, origBytes);
}
assertArrayEquals(origBytes, cb.get(0, origBytes.length));
}
@Test
public void testReadOnlyChainedBuffer() throws IOException {
ChainedBuffer cb = new ChainedBuffer(128 * 1024, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(128 * 1024, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] origBytes = new byte[128 * 1024];
Arrays.fill(origBytes, (byte) '1');
assertEquals(origBytes.length, cb.put(0, origBytes));
@ -89,7 +102,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
@Test
public void testFillChainnedBuffer() throws IOException {
ChainedBuffer cb = new ChainedBuffer(BIG_DATA_SIZE, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(BIG_DATA_SIZE, obfuscated, sourceData, sourceDataOffset, mgr);
// Fill
cb.fill(0, BIG_DATA_SIZE - 1, (byte) 0x12);
@ -114,7 +128,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
@Test
public void testBigChainnedBuffer() throws IOException {
ChainedBuffer cb = new ChainedBuffer(BIG_DATA_SIZE, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(BIG_DATA_SIZE, obfuscated, sourceData, sourceDataOffset, mgr);
// Fill
int cnt = BIG_DATA_SIZE / 4;
@ -157,7 +172,7 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
byte[] checkBytes = new byte[size];
int nextIndex;
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, mgr);
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, sourceData, sourceDataOffset, mgr);
// Write to entire buffer.
nextIndex = cb.put(0, bytes0);
@ -245,7 +260,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
Arrays.fill(origBytes, (byte) 'a');
System.arraycopy(origBytes, 0, newBytes, 0, size);
ChainedBuffer cb = new ChainedBuffer(origBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(origBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.put(0, origBytes);
newBytes[100] = (byte) 'B';
@ -278,24 +294,33 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
@Test
public void testGetByte() throws IOException {
int size = 800;
byte[] bytes = new byte[size];
byte[] bytes = new byte[size / 2];
Arrays.fill(bytes, (byte) 'a');
bytes[120] = (byte) 'W';
bytes[299] = (byte) 0x02;
bytes[360] = (byte) 'x';
bytes[799] = (byte) 0x02;
ChainedBuffer cb = new ChainedBuffer(bytes.length, obfuscated, mgr);
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, sourceData, sourceDataOffset, mgr);
cb.getByte(0);// uninitialized data
cb.getByte(size - 1);// uninitialized data
assertEquals(sourceData != null ? sourceData.getByte(sourceDataOffset) : 0, cb.getByte(0));// uninitialized data
assertEquals(sourceData != null ? sourceData.getByte(sourceDataOffset + (size - 1)) : 0,
cb.getByte(size - 1));// uninitialized data
cb.put(0, bytes);
int baseIndex = 50;
cb.put(baseIndex, bytes);
assertEquals(cb.getByte(0), (byte) 'a');
assertEquals(cb.getByte(120), (byte) 'W');
assertEquals(cb.getByte(360), (byte) 'x');
assertEquals(cb.getByte(399), (byte) 'a');
assertEquals(cb.getByte(799), (byte) 0x02);
assertEquals(cb.getByte(baseIndex + 0), (byte) 'a');
assertEquals(cb.getByte(baseIndex + 120), (byte) 'W');
assertEquals(cb.getByte(baseIndex + 299), (byte) 0x02);
assertEquals(cb.getByte(baseIndex + 360), (byte) 'x');
assertEquals(cb.getByte(baseIndex + 399), (byte) 'a');
assertEquals(sourceData != null ? sourceData.getByte(sourceDataOffset + 20) : 0,
cb.getByte(20));
assertEquals(sourceData != null ? sourceData.getByte(sourceDataOffset + 450) : 0,
cb.getByte(450));
assertEquals(sourceData != null ? sourceData.getByte(sourceDataOffset + 700) : 0,
cb.getByte(700));
try {
cb.getByte(-1);
@ -323,7 +348,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
Arrays.fill(origBytes, (byte) 'a');
System.arraycopy(origBytes, 0, newBytes, 0, size);
ChainedBuffer cb = new ChainedBuffer(origBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(origBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.put(0, origBytes);
newBytes[100] = (byte) 0x12;
@ -402,7 +428,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
int value3 = 0x77777777;
int value = 0x47474747;
ChainedBuffer cb = new ChainedBuffer(newBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(newBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.getInt(0);// uninitialized data
cb.getInt(size - 4);// uninitialized data
@ -450,7 +477,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
Arrays.fill(origBytes, (byte) 'b');
System.arraycopy(origBytes, 0, newBytes, 0, size);
ChainedBuffer cb = new ChainedBuffer(origBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(origBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.put(0, origBytes);
newBytes[100] = (byte) 0x12;
@ -553,7 +581,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
long value3 = 0x7777777777777777L;
long value = 0x4747474747474747L;
ChainedBuffer cb = new ChainedBuffer(newBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(newBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.getLong(0);// uninitialized data
cb.getLong(size - 8);// uninitialized data
@ -601,7 +630,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
Arrays.fill(origBytes, (byte) 'a');
System.arraycopy(origBytes, 0, newBytes, 0, size);
ChainedBuffer cb = new ChainedBuffer(origBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(origBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.put(0, origBytes);
newBytes[100] = (byte) 0x12;
@ -668,7 +698,8 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
short value3 = 0x7777;
short value = 0x4747;
ChainedBuffer cb = new ChainedBuffer(newBytes.length, obfuscated, mgr);
ChainedBuffer cb =
new ChainedBuffer(newBytes.length, obfuscated, sourceData, sourceDataOffset, mgr);
cb.getShort(0);// uninitialized data
cb.getShort(size - 2);// uninitialized data
@ -711,7 +742,7 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
public void testGetId() throws IOException {
int size = 400;
ChainedBuffer cb = new ChainedBuffer(32768, obfuscated, mgr);
ChainedBuffer cb = new ChainedBuffer(32768, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] bytes = new byte[size];
random.nextBytes(bytes);
cb.put(0, bytes);
@ -724,7 +755,7 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
@Test
public void testDelete() throws IOException {
ChainedBuffer cb = new ChainedBuffer(32768, obfuscated, mgr);
ChainedBuffer cb = new ChainedBuffer(32768, obfuscated, sourceData, sourceDataOffset, mgr);
int id = cb.getId();
cb.delete();
assertEquals(-1, cb.getId());
@ -740,7 +771,7 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
}
private void doSplitTest(int size) throws IOException {
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, mgr);
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] bytes = new byte[size];
random.nextBytes(bytes);
cb.put(0, bytes);
@ -767,17 +798,30 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
private void doAppendTest(int size1, int size2) throws IOException {
ChainedBuffer cb1 = new ChainedBuffer(size1, obfuscated, mgr);
ChainedBuffer cb1 = new ChainedBuffer(size1, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] bytes1 = new byte[size1];
random.nextBytes(bytes1);
cb1.put(0, bytes1);
ChainedBuffer cb2 = new ChainedBuffer(size2, obfuscated, mgr);
ChainedBuffer cb2 = new ChainedBuffer(size2, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] bytes2 = new byte[size2];
random.nextBytes(bytes2);
cb2.put(0, bytes2);
cb1.append(cb2);
try {
cb1.append(cb2);
if (sourceData != null) {
fail("Buffers with source data should have thrown exception");
}
}
catch (UnsupportedOperationException e) {
if (sourceData == null) {
e.printStackTrace();
fail("unexpected exception");
}
return;
}
assertEquals(size1 + size2, cb1.length());
// Make sure cb2 no longer exists
@ -786,6 +830,7 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
assertTrue(Arrays.equals(bytes1, cb1.get(0, size1)));
assertTrue(Arrays.equals(bytes2, cb1.get(size1, size2)));
assertEquals(0, mgr.getLockCount());
}
@Test
@ -808,12 +853,30 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
return true;
}
private boolean doSetSize(ChainedBuffer cb, int newSize, boolean preserveData)
throws IOException {
try {
cb.setSize(newSize, preserveData);
if (sourceData != null) {
fail("Buffers with source data should have thrown exception");
}
return true;
}
catch (UnsupportedOperationException e) {
if (sourceData == null) {
e.printStackTrace();
fail("unexpected exception");
}
}
return false;
}
@Test
public void testSetSize() throws IOException {
// start with small buffer
int size = BUFFER_SIZE / 2;
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, mgr);
ChainedBuffer cb = new ChainedBuffer(size, obfuscated, sourceData, sourceDataOffset, mgr);
byte[] bytes = new byte[size];
random.nextBytes(bytes);
cb.put(0, bytes);
@ -822,57 +885,61 @@ public abstract class AbstractChainedBufferTest extends AbstractGenericTest {
// Grow buffer (single index buffer)
int newSize = 2 * BUFFER_SIZE;
cb.setSize(newSize, true);
assertTrue(Arrays.equals(bytes, cb.get(0, size)));
int addSize = newSize - size;
byte[] addBytes = new byte[addSize];
random.nextBytes(addBytes);
cb.put(size, addBytes);
assertTrue(Arrays.equals(bytes, cb.get(0, size)));
assertTrue(Arrays.equals(addBytes, cb.get(size, addSize)));
bytes = cb.get(0, newSize);
size = newSize;
assertEquals(cb.length(), size);
assertEquals(bytes.length, size);
assertEquals(0, mgr.getLockCount());
if (doSetSize(cb, newSize, true)) {
assertTrue(Arrays.equals(bytes, cb.get(0, size)));
int addSize = newSize - size;
byte[] addBytes = new byte[addSize];
random.nextBytes(addBytes);
cb.put(size, addBytes);
assertTrue(Arrays.equals(bytes, cb.get(0, size)));
assertTrue(Arrays.equals(addBytes, cb.get(size, addSize)));
bytes = cb.get(0, newSize);
size = newSize;
assertEquals(cb.length(), size);
assertEquals(bytes.length, size);
assertEquals(0, mgr.getLockCount());
}
// Grow buffer (multiple index buffers)
newSize = (BUFFER_SIZE / 8) * BUFFER_SIZE;
cb.setSize(newSize, true);
addSize = newSize - size;
addBytes = new byte[addSize];
random.nextBytes(addBytes);
cb.put(size, addBytes);
assertTrue(Arrays.equals(bytes, cb.get(0, size)));
assertTrue(Arrays.equals(addBytes, cb.get(size, addSize)));
bytes = cb.get(0, newSize);
size = newSize;
assertEquals(cb.length(), size);
assertEquals(bytes.length, size);
assertEquals(0, mgr.getLockCount());
if (doSetSize(cb, newSize, true)) {
int addSize = newSize - size;
byte[] addBytes = new byte[addSize];
random.nextBytes(addBytes);
cb.put(size, addBytes);
assertTrue(Arrays.equals(bytes, cb.get(0, size)));
assertTrue(Arrays.equals(addBytes, cb.get(size, addSize)));
bytes = cb.get(0, newSize);
size = newSize;
assertEquals(cb.length(), size);
assertEquals(bytes.length, size);
assertEquals(0, mgr.getLockCount());
}
// Shrink buffer (single index buffer)
newSize = 2 * BUFFER_SIZE;
cb.setSize(newSize, true);
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
bytes = new byte[newSize];
random.nextBytes(bytes);
cb.put(0, bytes);
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
size = newSize;
assertEquals(cb.length(), size);
assertEquals(0, mgr.getLockCount());
if (doSetSize(cb, newSize, true)) {
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
bytes = new byte[newSize];
random.nextBytes(bytes);
cb.put(0, bytes);
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
size = newSize;
assertEquals(cb.length(), size);
assertEquals(0, mgr.getLockCount());
}
// Shrink to small buffer
newSize = BUFFER_SIZE / 2;
cb.setSize(newSize, true);
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
bytes = new byte[newSize];
random.nextBytes(bytes);
cb.put(0, bytes);
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
size = newSize;
assertEquals(cb.length(), size);
assertEquals(0, mgr.getLockCount());
if (doSetSize(cb, newSize, true)) {
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
bytes = new byte[newSize];
random.nextBytes(bytes);
cb.put(0, bytes);
assertTrue(equals(bytes, 0, cb.get(0, newSize), 0, newSize));
size = newSize;
assertEquals(cb.length(), size);
assertEquals(0, mgr.getLockCount());
}
}
}

View file

@ -18,6 +18,6 @@ package db;
public class ChainedBufferTest extends AbstractChainedBufferTest {
public ChainedBufferTest() {
super(false);
super(false, null, -1);
}
}

View file

@ -18,6 +18,6 @@ package db;
public class ObfuscatedChaninedBufferTest extends AbstractChainedBufferTest {
public ObfuscatedChaninedBufferTest() {
super(true);
super(true, null, -1);
}
}

View file

@ -0,0 +1,118 @@
/* ###
* IP: GHIDRA
*
* 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 db;
import java.io.IOException;
public class ObfuscatedSourcedChaninedBufferTest extends AbstractChainedBufferTest {
private static final int SOURCE_OFFSET = 24;
public ObfuscatedSourcedChaninedBufferTest() {
super(true, new Buffer() {
@Override
public int getId() {
return 0;
}
@Override
public int length() {
return Integer.MAX_VALUE;
}
@Override
public void get(int offset, byte[] bytes) throws IOException {
for (int i = 0; i < bytes.length; i++) {
bytes[i] = getByte(offset++);
}
}
@Override
public void get(int offset, byte[] data, int dataOffset, int length)
throws IOException {
for (int i = 0; i < length; i++) {
data[dataOffset++] = getByte(offset++);
}
}
@Override
public byte[] get(int offset, int length) throws IOException {
byte[] data = new byte[length];
get(offset, data);
return data;
}
@Override
public byte getByte(int offset) throws IOException {
return (byte) ~offset;
}
@Override
public int getInt(int offset) throws IOException {
byte[] data = get(offset, 4);
return ((data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) |
((data[2] & 0xff) << 8) | (data[3] & 0xff);
}
@Override
public short getShort(int offset) throws IOException {
byte[] data = get(offset, 2);
return (short) (((data[0] & 0xff) << 8) | (data[1] & 0xff));
}
@Override
public long getLong(int offset) throws IOException {
byte[] data = get(offset, 8);
return (((long) data[0] & 0xff) << 56) | (((long) data[1] & 0xff) << 48) |
(((long) data[2] & 0xff) << 40) | (((long) data[3] & 0xff) << 32) |
(((long) data[4] & 0xff) << 24) | (((long) data[5] & 0xff) << 16) |
(((long) data[6] & 0xff) << 8) | ((long) data[7] & 0xff);
}
@Override
public int put(int offset, byte[] data, int dataOffset, int length) throws IOException {
return 0;
}
@Override
public int put(int offset, byte[] bytes) throws IOException {
return 0;
}
@Override
public int putByte(int offset, byte b) throws IOException {
return 0;
}
@Override
public int putInt(int offset, int v) throws IOException {
return 0;
}
@Override
public int putShort(int offset, short v) throws IOException {
return 0;
}
@Override
public int putLong(int offset, long v) throws IOException {
return 0;
}
}, SOURCE_OFFSET);
}
}