162 lines
6.5 KiB
Java
162 lines
6.5 KiB
Java
/* ====================================================================
|
|
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.hssf.record;
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
import junit.framework.AssertionFailedError;
|
|
import junit.framework.TestCase;
|
|
|
|
import org.apache.poi.util.HexRead;
|
|
import org.apache.poi.util.LittleEndian;
|
|
|
|
/**
|
|
* Tests Subrecord components of an OBJ record. Test data taken directly
|
|
* from a real Excel file.
|
|
*
|
|
* @author Michael Zalewski (zalewski@optonline.net)
|
|
*/
|
|
public final class TestSubRecord extends TestCase {
|
|
/*
|
|
The following is a dump of the OBJ record corresponding to an auto-filter
|
|
drop-down list. The 3rd subrecord beginning at offset 0x002e (type=0x0013)
|
|
does not conform to the documentation, because the length field is 0x1fee,
|
|
which is longer than the entire OBJ record.
|
|
|
|
00000000 15 00 12 00 14 00 01 00 01 21 00 00 00 00 3C 13 .........!....<. Type=0x15 Len=0x0012 ftCmo
|
|
00000010 F4 03 00 00 00 00
|
|
0C 00 14 00 00 00 00 00 00 00 ................ Type=0x0c Len=0x0014 ftSbs
|
|
00000020 00 00 00 00 01 00 08 00 00 00 10 00 00 00
|
|
13 00 ................ Type=0x13 Len=0x1FEE ftLbsData
|
|
00000030 EE 1F 00 00 08 00 08 00 01 03 00 00 0A 00 14 00 ................
|
|
00000040 6C 00
|
|
00 00 00 00 l..... Type=0x00 Len=0x0000 ftEnd
|
|
*/
|
|
|
|
private static final byte[] dataAutoFilter
|
|
= HexRead.readFromString(""
|
|
+ "5D 00 46 00 " // ObjRecord.sid, size=70
|
|
// ftCmo
|
|
+ "15 00 12 00 "
|
|
+ "14 00 01 00 01 00 01 21 00 00 3C 13 F4 03 00 00 00 00 "
|
|
// ftSbs (currently UnknownSubrecord)
|
|
+ "0C 00 14 00 "
|
|
+ "00 00 00 00 00 00 00 00 00 00 01 00 08 00 00 00 10 00 00 00 "
|
|
// ftLbsData (currently UnknownSubrecord)
|
|
+ "13 00 EE 1F 00 00 "
|
|
+ "08 00 08 00 01 03 00 00 0A 00 14 00 6C 00 "
|
|
// ftEnd
|
|
+ "00 00 00 00"
|
|
);
|
|
|
|
|
|
/**
|
|
* Make sure that ftLbsData (which has abnormal size info) is parsed correctly.
|
|
* If the size field is interpreted incorrectly, the resulting ObjRecord becomes way too big.
|
|
* At the time of fixing (Oct-2008 svn r707447) {@link RecordInputStream} allowed buffer
|
|
* read overruns, so the bug was mostly silent.
|
|
*/
|
|
public void testReadAll_bug45778() {
|
|
RecordInputStream in = TestcaseRecordInputStream.create(dataAutoFilter);
|
|
ObjRecord or = new ObjRecord(in);
|
|
byte[] data2 = or.serialize();
|
|
if (data2.length == 8228) {
|
|
throw new AssertionFailedError("Identified bug 45778");
|
|
}
|
|
assertEquals(74, data2.length);
|
|
assertTrue(Arrays.equals(dataAutoFilter, data2));
|
|
}
|
|
|
|
public void testReadManualComboWithFormula() {
|
|
byte[] data = HexRead.readFromString(""
|
|
+ "5D 00 66 00 "
|
|
+ "15 00 12 00 14 00 02 00 11 20 00 00 00 00 "
|
|
+ "20 44 C6 04 00 00 00 00 0C 00 14 00 04 F0 C6 04 "
|
|
+ "00 00 00 00 00 00 01 00 06 00 00 00 10 00 00 00 "
|
|
+ "0E 00 0C 00 05 00 80 44 C6 04 24 09 00 02 00 02 "
|
|
+ "13 00 DE 1F 10 00 09 00 80 44 C6 04 25 0A 00 0F "
|
|
+ "00 02 00 02 00 02 06 00 03 00 08 00 00 00 00 00 "
|
|
+ "08 00 00 00 00 00 00 00 " // TODO sometimes last byte is non-zero
|
|
);
|
|
|
|
RecordInputStream in = TestcaseRecordInputStream.create(data);
|
|
ObjRecord or = new ObjRecord(in);
|
|
byte[] data2 = or.serialize();
|
|
if (data2.length == 8228) {
|
|
throw new AssertionFailedError("Identified bug 45778");
|
|
}
|
|
assertEquals("Encoded length", data.length, data2.length);
|
|
for (int i = 0; i < data.length; i++) {
|
|
if (data[i] != data2[i]) {
|
|
throw new AssertionFailedError("Encoded data differs at index " + i);
|
|
}
|
|
}
|
|
assertTrue(Arrays.equals(data, data2));
|
|
}
|
|
|
|
/**
|
|
* Some versions of POI (e.g. 3.1 - prior to svn r707450 / bug 45778) interpreted the ftLbs
|
|
* subrecord second short (0x1FEE) as a length, and hence read lots of extra padding. This
|
|
* buffer-overrun in {@link RecordInputStream} happened silently due to problems later fixed
|
|
* in svn 707778. When the ObjRecord is written, the extra padding is written too, making the
|
|
* record 8224 bytes long instead of 70.
|
|
* (An aside: It seems more than a coincidence that this problem creates a record of exactly
|
|
* {@link RecordInputStream#MAX_RECORD_DATA_SIZE} but not enough is understood about
|
|
* subrecords to explain this.)<br/>
|
|
*
|
|
* Excel reads files with this excessive padding OK. It also truncates the over-sized
|
|
* ObjRecord back to the proper size. POI should do the same.
|
|
*/
|
|
public void testWayTooMuchPadding_bug46545() {
|
|
byte[] data = HexRead.readFromString(""
|
|
+ "15 00 12 00 14 00 13 00 01 21 00 00 00"
|
|
+ "00 98 0B 5B 09 00 00 00 00 0C 00 14 00 00 00 00 00 00 00 00"
|
|
+ "00 00 00 01 00 01 00 00 00 10 00 00 00 "
|
|
// ftLbs
|
|
+ "13 00 EE 1F 00 00 "
|
|
+ "01 00 00 00 01 06 00 00 02 00 08 00 75 00 "
|
|
// ftEnd
|
|
+ "00 00 00 00"
|
|
);
|
|
final int LBS_START_POS = 0x002E;
|
|
final int WRONG_LBS_SIZE = 0x1FEE;
|
|
assertEquals(0x0013, LittleEndian.getShort(data, LBS_START_POS+0));
|
|
assertEquals(WRONG_LBS_SIZE, LittleEndian.getShort(data, LBS_START_POS+2));
|
|
int wrongTotalSize = LBS_START_POS + 4 + WRONG_LBS_SIZE;
|
|
byte[] wrongData = new byte[wrongTotalSize];
|
|
System.arraycopy(data, 0, wrongData, 0, data.length);
|
|
// wrongData has the ObjRecord data as would have been written by v3.1
|
|
|
|
RecordInputStream in = TestcaseRecordInputStream.create(ObjRecord.sid, wrongData);
|
|
ObjRecord or;
|
|
try {
|
|
or = new ObjRecord(in);
|
|
} catch (RecordFormatException e) {
|
|
if (e.getMessage().startsWith("Leftover 8154 bytes in subrecord data")) {
|
|
throw new AssertionFailedError("Identified bug 46545");
|
|
}
|
|
throw e;
|
|
}
|
|
// make sure POI properly truncates the ObjRecord data
|
|
byte[] data2 = or.serialize();
|
|
TestcaseRecordInputStream.confirmRecordEncoding(ObjRecord.sid, data, data2);
|
|
}
|
|
}
|