added LittleEndianByteArrayInputStream

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@707534 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-10-24 03:47:42 +00:00
parent 326cf2c32d
commit 21a68aae0e
16 changed files with 192 additions and 63 deletions

View File

@ -26,7 +26,9 @@ import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
@ -156,12 +158,7 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
}
private static Ptg readRefPtg(byte[] formulaRawBytes) {
byte[] data = new byte[formulaRawBytes.length + 4];
LittleEndian.putUShort(data, 0, -5555);
LittleEndian.putUShort(data, 2, formulaRawBytes.length);
System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
in.nextRecord();
LittleEndianInput in = new LittleEndianInputStream(new ByteArrayInputStream(formulaRawBytes));
byte ptgSid = in.readByte();
switch(ptgSid) {
case AreaPtg.sid: return new AreaPtg(in);

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.LittleEndianOutputStream;
@ -209,17 +210,12 @@ public abstract class SubRecord {
out.writeShort(_unknownShort13);
}
private static Ptg readRefPtg(byte[] formulaRawBytes) {
byte[] data = new byte[formulaRawBytes.length + 4];
LittleEndian.putUShort(data, 0, -5555);
LittleEndian.putUShort(data, 2, formulaRawBytes.length);
System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
in.nextRecord();
byte ptgSid = in.readByte();
LittleEndianInput in = new LittleEndianByteArrayInputStream(formulaRawBytes);
byte ptgSid = in.readByte();
switch(ptgSid) {
case AreaPtg.sid: return new AreaPtg(in);
case Area3DPtg.sid: return new Area3DPtg(in);
case RefPtg.sid: return new RefPtg(in);
case RefPtg.sid: return new RefPtg(in);
case Ref3DPtg.sid: return new Ref3DPtg(in);
}
return null;

View File

@ -0,0 +1,133 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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 org.apache.poi.util;
/**
* Adapts a plain byte array to {@link LittleEndianInput}
*
*
* @author Josh Micich
*/
public final class LittleEndianByteArrayInputStream implements LittleEndianInput {
private final byte[] _buf;
private final int _endIndex;
private int _readIndex;
public LittleEndianByteArrayInputStream(byte[] buf, int startOffset, int maxReadLen) {
_buf = buf;
_readIndex = startOffset;
_endIndex = startOffset + maxReadLen;
}
public LittleEndianByteArrayInputStream(byte[] buf, int startOffset) {
this(buf, startOffset, buf.length - startOffset);
}
public LittleEndianByteArrayInputStream(byte[] buf) {
this(buf, 0, buf.length);
}
private void checkPosition(int i) {
if (i > _endIndex - _readIndex) {
throw new RuntimeException("Buffer overrun");
}
}
public int getReadIndex() {
return _readIndex;
}
public byte readByte() {
checkPosition(1);
return _buf[_readIndex++];
}
public int readInt() {
checkPosition(4);
int i = _readIndex;
int b0 = _buf[i++] & 0xFF;
int b1 = _buf[i++] & 0xFF;
int b2 = _buf[i++] & 0xFF;
int b3 = _buf[i++] & 0xFF;
_readIndex = i;
return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
}
public long readLong() {
checkPosition(8);
int i = _readIndex;
int b0 = _buf[i++] & 0xFF;
int b1 = _buf[i++] & 0xFF;
int b2 = _buf[i++] & 0xFF;
int b3 = _buf[i++] & 0xFF;
int b4 = _buf[i++] & 0xFF;
int b5 = _buf[i++] & 0xFF;
int b6 = _buf[i++] & 0xFF;
int b7 = _buf[i++] & 0xFF;
_readIndex = i;
return (((long)b7 << 56) +
((long)b6 << 48) +
((long)b5 << 40) +
((long)b4 << 32) +
((long)b3 << 24) +
(b2 << 16) +
(b1 << 8) +
(b0 << 0));
}
public short readShort() {
return (short)readUShort();
}
public int readUByte() {
checkPosition(1);
return _buf[_readIndex++] & 0xFF;
}
public int readUShort() {
checkPosition(2);
int i = _readIndex;
int b0 = _buf[i++] & 0xFF;
int b1 = _buf[i++] & 0xFF;
_readIndex = i;
return (b1 << 8) + (b0 << 0);
}
public void readFully(byte[] buf, int off, int len) {
checkPosition(len);
System.arraycopy(_buf, _readIndex, _buf, off, len);
_readIndex+=len;
}
public void readFully(byte[] buf) {
readFully(buf, 0, buf.length);
}
public double readDouble() {
return Double.longBitsToDouble(readLong());
}
public String readCompressedUnicode(int nChars) {
checkPosition(nChars);
char[] buf = new char[nChars];
for (int i = 0; i < buf.length; i++) {
buf[i] = (char) readUByte();
}
return new String(buf);
}
public String readUnicodeLEString(int nChars) {
checkPosition(nChars*2);
char[] buf = new char[nChars];
for (int i = 0; i < buf.length; i++) {
buf[i] = (char) readUShort();
}
return new String(buf);
}
}

View File

@ -37,7 +37,7 @@ public final class TestCommonObjectDataSubRecord extends TestCase {
};
public void testLoad() {
CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.createWithFakeSid(data), data.length);
CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.createLittleEndian(data), data.length);
assertEquals( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX, record.getObjectType());
assertEquals((short) 1, record.getObjectId());

View File

@ -14,11 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.util.HexRead;
@ -37,33 +38,43 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
public void testStore() {
byte[] src = hr(data1);
src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);
// src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(src));
in.nextRecord();
RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, src);
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length-4);
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length);
byte[] ser = record1.serialize();
RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));
in2.nextRecord();
RecordInputStream in2 = TestcaseRecordInputStream.create(ser);
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
assertTrue(Arrays.equals(src, ser));
confirmData(src, ser);
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
byte[] ser2 = record1.serialize();
assertTrue(Arrays.equals(ser, ser2));
}
/**
* @param expectedData does not include sid & size
* @param actualFullRecordData includes sid & size
*/
private static void confirmData(byte[] expectedData, byte[] actualFullRecordData) {
assertEquals(expectedData.length, actualFullRecordData.length-4);
for (int i = 0; i < expectedData.length; i++) {
if(expectedData[i] != actualFullRecordData[i+4]) {
throw new AssertionFailedError("Difference at offset (" + i + ")");
}
}
}
public void testCreate() {
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord();
byte[] ser = record1.serialize();
RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));
in2.nextRecord();
RecordInputStream in2 = TestcaseRecordInputStream.create(ser);
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
@ -78,21 +89,17 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
* taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).
*/
private static final byte[] data45912 = hr(
"09 00 14 00 " +
"12 00 0B 00 F8 02 88 04 3B 00 " +
"00 00 00 01 00 00 00 01 " +
"00 00");
public void testCameraTool_bug45912() {
byte[] data = data45912;
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
in.nextRecord();
RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);
EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length-4);
EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);
byte[] ser2 = rec.serialize();
assertTrue(Arrays.equals(data, ser2));
confirmData(data, ser2);
}
private static byte[] hr(String string) {

View File

@ -119,7 +119,6 @@ public final class TestFormulaRecord extends TestCase {
public void testWithConcat() {
// =CHOOSE(2,A2,A3,A4)
byte[] data = {
6, 0, 68, 0,
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
64, 0, 0, 12, 0, 12, -4, 46, 0,
30, 2, 0, // Int - 2
@ -134,8 +133,7 @@ public final class TestFormulaRecord extends TestCase {
25, 8, 3, 0, // Attr
66, 4, 100, 0 // CHOOSE
};
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
inp.nextRecord();
RecordInputStream inp = TestcaseRecordInputStream.create(FormatRecord.sid, data);
FormulaRecord fr = new FormulaRecord(inp);

View File

@ -239,8 +239,7 @@ public final class TestHyperlinkRecord extends TestCase {
RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data);
HyperlinkRecord link = new HyperlinkRecord(is);
byte[] bytes1 = link.serialize();
is = new RecordInputStream(new ByteArrayInputStream(bytes1));
is.nextRecord();
is = TestcaseRecordInputStream.create(bytes1);
link = new HyperlinkRecord(is);
byte[] bytes2 = link.serialize();
assertEquals(bytes1.length, bytes2.length);

View File

@ -23,6 +23,7 @@ import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.util.LittleEndianInput;
/**
* @author Josh Micich
@ -59,7 +60,7 @@ public final class TestSharedFormulaRecord extends TestCase {
*/
public void testConvertSharedFormulasOperandClasses_bug45123() {
RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
int encodedLen = in.readUShort();
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);

View File

@ -55,11 +55,9 @@ public final class TestTextObjectBaseRecord extends TestCase {
public void testLoad() {
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
in.nextRecord();
RecordInputStream in = TestcaseRecordInputStream.create(data);
TextObjectRecord record = new TextObjectRecord(in);
assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment());
assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment());
assertEquals(true, record.isTextLocked());

View File

@ -52,8 +52,7 @@ public final class TestTextObjectRecord extends TestCase {
public void testRead() {
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
is.nextRecord();
RecordInputStream is =TestcaseRecordInputStream.create(simpleData);
TextObjectRecord record = new TextObjectRecord(is);
assertEquals(TextObjectRecord.sid, record.getSid());
@ -79,8 +78,7 @@ public final class TestTextObjectRecord extends TestCase {
assertTrue(Arrays.equals(simpleData, ser));
//read again
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
is.nextRecord();
RecordInputStream is = TestcaseRecordInputStream.create(simpleData);
record = new TextObjectRecord(is);
}
@ -101,8 +99,7 @@ public final class TestTextObjectRecord extends TestCase {
assertEquals(22, ser.length); // just the TXO record
//read again
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));
is.nextRecord();
RecordInputStream is = TestcaseRecordInputStream.create(ser);
record = new TextObjectRecord(is);
assertEquals(0, record.getStr().length());
}

View File

@ -23,6 +23,8 @@ import java.io.InputStream;
import junit.framework.Assert;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianInput;
/**
* A Record Input Stream derivative that makes access to byte arrays used in the
@ -40,8 +42,8 @@ public final class TestcaseRecordInputStream {
/**
* Prepends a mock record identifier to the supplied data and opens a record input stream
*/
public static RecordInputStream createWithFakeSid(byte[] data) {
return create(-5555, data);
public static LittleEndianInput createLittleEndian(byte[] data) {
return new LittleEndianByteArrayInputStream(data);
}
public static RecordInputStream create(int sid, byte[] data) {

View File

@ -21,12 +21,12 @@ import java.util.Arrays;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.util.HexRead;
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianInput;
/**
*
* @author Josh Micich
@ -61,7 +61,7 @@ public final class TestConstantValueParser extends TestCase {
}
}
public void testDecode() {
RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SAMPLE_ENCODING);
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SAMPLE_ENCODING);
Object[] values = ConstantValueParser.parse(in, 4);
for (int i = 0; i < values.length; i++) {

View File

@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianInput;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
@ -55,9 +56,9 @@ public final class TestArrayPtg extends TestCase {
*/
public void testReadWriteTokenValueBytes() {
ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
Object[][] values = ptg.getTokenArrayValues();
@ -83,8 +84,8 @@ public final class TestArrayPtg extends TestCase {
* Excel stores array elements column by column. This test makes sure POI does the same.
*/
public void testElementOrdering() {
ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
@ -114,9 +115,9 @@ public final class TestArrayPtg extends TestCase {
}
public void testToFormulaString() {
ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
String actualFormula;
try {
@ -147,7 +148,7 @@ public final class TestArrayPtg extends TestCase {
// Force encoded operand class for tArray
fullData[0] = (byte) (ArrayPtg.sid + operandClass);
RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(fullData);
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(fullData);
Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in);
assertEquals(1, ptgs.length);

View File

@ -21,9 +21,9 @@ import java.util.Arrays;
import junit.framework.AssertionFailedError;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.util.HexRead;
import org.apache.poi.util.LittleEndianInput;
/**
* Tests for {@link AttrPtg}.
@ -37,7 +37,7 @@ public final class TestAttrPtg extends AbstractPtgTestCase {
*/
public void testReserializeAttrChoose() {
byte[] data = HexRead.readFromString("19, 04, 03, 00, 08, 00, 11, 00, 1A, 00, 23, 00");
RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(data);
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(data);
Ptg[] ptgs = Ptg.readTokens(data.length, in);
byte[] data2 = new byte[data.length];
try {

View File

@ -34,7 +34,7 @@ public final class TestFuncPtg extends TestCase {
0,
};
FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createWithFakeSid(fakeData) );
FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createLittleEndian(fakeData) );
assertEquals( "Len formula index is not 32(20H)", 0x20, ptg.getFunctionIndex() );
assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() );
assertEquals( "Function Name", "LEN", ptg.getName() );

View File

@ -23,10 +23,10 @@ import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndianInput;
/**
* Tests for {@link RefPtg}.
@ -94,7 +94,7 @@ public final class TestReferencePtg extends TestCase {
0x2C, 33, 44, 55, 66,
};
public void testReadWrite_tRefN_bug45091() {
RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(tRefN_data);
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(tRefN_data);
Ptg[] ptgs = Ptg.readTokens(tRefN_data.length, in);
byte[] outData = new byte[5];
Ptg.serializePtgs(ptgs, outData, 0);