More work on FeatRecord/Shared Features. More is still needed though, it's still WIP

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@894018 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2009-12-26 19:57:09 +00:00
parent e536251666
commit 869fc4e5a6
13 changed files with 264 additions and 19 deletions

View File

@ -162,6 +162,8 @@ public final class BiffViewer {
case ExtSSTRecord.sid: return new ExtSSTRecord(in); case ExtSSTRecord.sid: return new ExtSSTRecord(in);
case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in); case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in);
case ExternSheetRecord.sid: return new ExternSheetRecord(in); case ExternSheetRecord.sid: return new ExternSheetRecord(in);
case FeatRecord.sid: return new FeatRecord(in);
case FeatHdrRecord.sid: return new FeatHdrRecord(in);
case FilePassRecord.sid: return new FilePassRecord(in); case FilePassRecord.sid: return new FilePassRecord(in);
case FileSharingRecord.sid: return new FileSharingRecord(in); case FileSharingRecord.sid: return new FileSharingRecord(in);
case FnGroupCountRecord.sid: return new FnGroupCountRecord(in); case FnGroupCountRecord.sid: return new FnGroupCountRecord(in);

View File

@ -34,6 +34,7 @@ import org.apache.poi.hssf.record.DimensionsRecord;
import org.apache.poi.hssf.record.DrawingRecord; import org.apache.poi.hssf.record.DrawingRecord;
import org.apache.poi.hssf.record.DrawingSelectionRecord; import org.apache.poi.hssf.record.DrawingSelectionRecord;
import org.apache.poi.hssf.record.EOFRecord; import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.FeatRecord;
import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.GridsetRecord; import org.apache.poi.hssf.record.GridsetRecord;
import org.apache.poi.hssf.record.GutsRecord; import org.apache.poi.hssf.record.GutsRecord;
@ -341,7 +342,7 @@ final class RecordOrderer {
switch(sid) { switch(sid) {
case UnknownRecord.SHEETEXT_0862: case UnknownRecord.SHEETEXT_0862:
case UnknownRecord.SHEETPROTECTION_0867: case UnknownRecord.SHEETPROTECTION_0867:
case UnknownRecord.RANGEPROTECTION_0868: case FeatRecord.sid:
case EOFRecord.sid: case EOFRecord.sid:
return true; return true;
} }

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.common.FtrHeader;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
/** /**
@ -52,6 +53,7 @@ public final class FeatHdrRecord extends StandardRecord {
public final static short sid = 0x0867; public final static short sid = 0x0867;
private FtrHeader futureHeader;
private int isf_sharedFeatureType; // See SHAREDFEATURES_ private int isf_sharedFeatureType; // See SHAREDFEATURES_
private byte reserved; // Should always be one private byte reserved; // Should always be one
/** /**
@ -63,6 +65,8 @@ public final class FeatHdrRecord extends StandardRecord {
private byte[] rgbHdrData; private byte[] rgbHdrData;
public FeatHdrRecord() { public FeatHdrRecord() {
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
} }
public short getSid() { public short getSid() {
@ -70,9 +74,11 @@ public final class FeatHdrRecord extends StandardRecord {
} }
public FeatHdrRecord(RecordInputStream in) { public FeatHdrRecord(RecordInputStream in) {
futureHeader = new FtrHeader(in);
isf_sharedFeatureType = in.readShort(); isf_sharedFeatureType = in.readShort();
reserved = in.readByte(); reserved = in.readByte();
cbHdrData = in.readLong(); cbHdrData = in.readInt();
// Don't process this just yet, need the BOFRecord // Don't process this just yet, need the BOFRecord
rgbHdrData = in.readRemainder(); rgbHdrData = in.readRemainder();
} }
@ -88,13 +94,15 @@ public final class FeatHdrRecord extends StandardRecord {
} }
public void serialize(LittleEndianOutput out) { public void serialize(LittleEndianOutput out) {
futureHeader.serialize(out);
out.writeShort(isf_sharedFeatureType); out.writeShort(isf_sharedFeatureType);
out.writeByte(reserved); out.writeByte(reserved);
out.writeLong(cbHdrData); out.writeInt((int)cbHdrData);
out.write(rgbHdrData); out.write(rgbHdrData);
} }
protected int getDataSize() { protected int getDataSize() {
return 2+1+4+rgbHdrData.length; return 12 + 2+1+4+rgbHdrData.length;
} }
} }

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.common.FtrHeader;
import org.apache.poi.hssf.record.common.Ref8U; import org.apache.poi.hssf.record.common.Ref8U;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
@ -29,14 +30,14 @@ import org.apache.poi.util.LittleEndianOutput;
public final class FeatRecord extends StandardRecord { public final class FeatRecord extends StandardRecord {
public final static short sid = 0x0868; public final static short sid = 0x0868;
private FtrHeader futureHeader;
/** /**
* See SHAREDFEATURES_* on {@link FeatHdrRecord} * See SHAREDFEATURES_* on {@link FeatHdrRecord}
*/ */
private int isf_sharedFeatureType; private int isf_sharedFeatureType;
private byte reserved1; // Should always be zero private byte reserved1; // Should always be zero
private long reserved2; // Should always be zero private long reserved2; // Should always be zero
/** The number of refs */
private int cref;
/** Only matters if type is ISFFEC2 */ /** Only matters if type is ISFFEC2 */
private long cbFeatData; private long cbFeatData;
private int reserved3; // Should always be zero private int reserved3; // Should always be zero
@ -45,6 +46,8 @@ public final class FeatRecord extends StandardRecord {
private byte[] rgbFeat; private byte[] rgbFeat;
public FeatRecord() { public FeatRecord() {
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
} }
public short getSid() { public short getSid() {
@ -52,11 +55,13 @@ public final class FeatRecord extends StandardRecord {
} }
public FeatRecord(RecordInputStream in) { public FeatRecord(RecordInputStream in) {
futureHeader = new FtrHeader(in);
isf_sharedFeatureType = in.readShort(); isf_sharedFeatureType = in.readShort();
reserved1 = in.readByte(); reserved1 = in.readByte();
reserved2 = in.readLong(); reserved2 = in.readInt();
cref = in.readUShort(); int cref = in.readUShort();
cbFeatData = in.readLong(); cbFeatData = in.readInt();
reserved3 = in.readShort(); reserved3 = in.readShort();
cellRefs = new Ref8U[cref]; cellRefs = new Ref8U[cref];
@ -69,7 +74,7 @@ public final class FeatRecord extends StandardRecord {
public String toString() { public String toString() {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append("[SHARDED FEATURE]\n"); buffer.append("[SHARED FEATURE]\n");
// TODO ... // TODO ...
@ -78,13 +83,23 @@ public final class FeatRecord extends StandardRecord {
} }
public void serialize(LittleEndianOutput out) { public void serialize(LittleEndianOutput out) {
futureHeader.serialize(out);
out.writeShort(isf_sharedFeatureType); out.writeShort(isf_sharedFeatureType);
out.writeByte(reserved1);
out.writeInt((int)reserved2);
out.writeShort(cellRefs.length);
out.writeInt((int)cbFeatData);
out.writeShort(reserved3);
// TODO ... for(int i=0; i<cellRefs.length; i++) {
cellRefs[i].serialize(out);
}
out.write(rgbFeat);
} }
protected int getDataSize() { protected int getDataSize() {
return -1; // TODO return 12 + 2+1+4+2+4+2+Ref8U.getDataSize()+rgbFeat.length;
} }
} }

View File

@ -143,6 +143,8 @@ public final class RecordFactory {
ExternalNameRecord.class, ExternalNameRecord.class,
ExternSheetRecord.class, ExternSheetRecord.class,
ExtSSTRecord.class, ExtSSTRecord.class,
FeatRecord.class,
FeatHdrRecord.class,
FilePassRecord.class, FilePassRecord.class,
FileSharingRecord.class, FileSharingRecord.class,
FnGroupCountRecord.class, FnGroupCountRecord.class,

View File

@ -234,12 +234,18 @@ public final class RecordInputStream implements LittleEndianInput {
return _dataInput.readShort(); return _dataInput.readShort();
} }
/**
* Reads a 32 bit, signed value
*/
public int readInt() { public int readInt() {
checkRecordPosition(LittleEndian.INT_SIZE); checkRecordPosition(LittleEndian.INT_SIZE);
_currentDataOffset += LittleEndian.INT_SIZE; _currentDataOffset += LittleEndian.INT_SIZE;
return _dataInput.readInt(); return _dataInput.readInt();
} }
/**
* Reads a 64 bit, signed value
*/
public long readLong() { public long readLong() {
checkRecordPosition(LittleEndian.LONG_SIZE); checkRecordPosition(LittleEndian.LONG_SIZE);
_currentDataOffset += LittleEndian.LONG_SIZE; _currentDataOffset += LittleEndian.LONG_SIZE;

View File

@ -56,7 +56,6 @@ public final class UnknownRecord extends StandardRecord {
public static final int QUICKTIP_0800 = 0x0800; public static final int QUICKTIP_0800 = 0x0800;
public static final int SHEETEXT_0862 = 0x0862; // OOO calls this SHEETLAYOUT public static final int SHEETEXT_0862 = 0x0862; // OOO calls this SHEETLAYOUT
public static final int SHEETPROTECTION_0867 = 0x0867; public static final int SHEETPROTECTION_0867 = 0x0867;
public static final int RANGEPROTECTION_0868 = 0x0868;
public static final int HEADER_FOOTER_089C = 0x089C; public static final int HEADER_FOOTER_089C = 0x089C;
private int _sid; private int _sid;
@ -173,7 +172,6 @@ public final class UnknownRecord extends StandardRecord {
case 0x0863: return "BOOKEXT"; case 0x0863: return "BOOKEXT";
case 0x0864: return "SXADDL"; // Pivot Table Additional Info case 0x0864: return "SXADDL"; // Pivot Table Additional Info
case SHEETPROTECTION_0867: return "SHEETPROTECTION"; case SHEETPROTECTION_0867: return "SHEETPROTECTION";
case RANGEPROTECTION_0868: return "RANGEPROTECTION";
case 0x086B: return "DATALABEXTCONTENTS"; case 0x086B: return "DATALABEXTCONTENTS";
case 0x086C: return "CELLWATCH"; case 0x086C: return "CELLWATCH";
case 0x0874: return "DROPDOWNOBJIDS"; case 0x0874: return "DROPDOWNOBJIDS";

View File

@ -0,0 +1,89 @@
/* ====================================================================
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.common;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndianOutput;
/**
* Title: FtrHeader (Future Record Header) common record part
* <P>
* This record part specifies a header for a Ftr (Future)
* style record, which includes extra attributes above and
* beyond those of a traditional record.
*/
public final class FtrHeader {
/** This MUST match the type on the containing record */
private short recordType;
/** This is a FrtFlags */
private short grbitFrt;
/** MUST be 8 bytes and all zero */
private byte[] reserved;
public FtrHeader() {
reserved = new byte[8];
}
public FtrHeader(RecordInputStream in) {
recordType = in.readShort();
grbitFrt = in.readShort();
reserved = new byte[8];
in.read(reserved, 0, 8);
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [FUTURE HEADER]\n");
buffer.append(" Type " + recordType);
buffer.append(" Flags " + grbitFrt);
buffer.append(" [/FUTURE HEADER]\n");
return buffer.toString();
}
public void serialize(LittleEndianOutput out) {
out.writeShort(recordType);
out.writeShort(grbitFrt);
out.write(reserved);
}
public static int getDataSize() {
return 12;
}
public short getRecordType() {
return recordType;
}
public void setRecordType(short recordType) {
this.recordType = recordType;
}
public short getGrbitFrt() {
return grbitFrt;
}
public void setGrbitFrt(short grbitFrt) {
this.grbitFrt = grbitFrt;
}
public byte[] getReserved() {
return reserved;
}
public void setReserved(byte[] reserved) {
this.reserved = reserved;
}
}

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.ContinueRecord;
import org.apache.poi.hssf.record.DVALRecord; import org.apache.poi.hssf.record.DVALRecord;
import org.apache.poi.hssf.record.DVRecord; import org.apache.poi.hssf.record.DVRecord;
import org.apache.poi.hssf.record.EOFRecord; import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.FeatHdrRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SelectionRecord; import org.apache.poi.hssf.record.SelectionRecord;
import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.WindowTwoRecord;
@ -86,9 +87,10 @@ public final class TestHSSFEventFactory extends TestCase {
// Check that the last few records are as we expect // Check that the last few records are as we expect
// (Makes sure we don't accidently skip the end ones) // (Makes sure we don't accidently skip the end ones)
int numRec = recs.length; int numRec = recs.length;
assertEquals(DVALRecord.class, recs[numRec-3].getClass()); assertEquals(DVALRecord.class, recs[numRec-4].getClass());
assertEquals(DVRecord.class, recs[numRec-2].getClass()); assertEquals(DVRecord.class, recs[numRec-3].getClass());
assertEquals(EOFRecord.class, recs[numRec-1].getClass()); assertEquals(FeatHdrRecord.class, recs[numRec-2].getClass());
assertEquals(EOFRecord.class, recs[numRec-1].getClass());
} }
/** /**
@ -110,7 +112,7 @@ public final class TestHSSFEventFactory extends TestCase {
} }
private static class MockHSSFListener implements HSSFListener { private static class MockHSSFListener implements HSSFListener {
private final List records = new ArrayList(); private final List<Record> records = new ArrayList<Record>();
public MockHSSFListener() {} public MockHSSFListener() {}
public Record[] getRecords() { public Record[] getRecords() {

View File

@ -0,0 +1,89 @@
/* ====================================================================
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 org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.hssf.usermodel.HSSFTestHelper;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import junit.framework.TestCase;
/**
* Tests for <tt>FeatRecord</tt>
*
* @author Josh Micich
*/
public final class TestFeatRecord extends TestCase {
public void testWithoutFeatRecord() throws Exception {
HSSFWorkbook hssf =
HSSFTestDataSamples.openSampleWorkbook("46136-WithWarnings.xls");
InternalWorkbook wb = HSSFTestHelper.getWorkbookForTest(hssf);
int countFR = 0;
int countFRH = 0;
for(Record r : wb.getRecords()) {
if(r instanceof FeatRecord) {
countFR++;
} else if (r.getSid() == FeatRecord.sid) {
countFR++;
}
if(r instanceof FeatHdrRecord) {
countFRH++;
} else if (r.getSid() == FeatHdrRecord.sid) {
countFRH++;
}
}
assertEquals(0, countFR);
assertEquals(0, countFRH);
}
/**
* TODO - make this work!
* (Need to have the Internal Workbook capture it or something)
*/
public void DISABLEDtestReadFeatRecord() throws Exception {
HSSFWorkbook hssf =
HSSFTestDataSamples.openSampleWorkbook("46136-NoWarnings.xls");
InternalWorkbook wb = HSSFTestHelper.getWorkbookForTest(hssf);
FeatRecord fr = null;
int countFR = 0;
int countFRH = 0;
for(Record r : wb.getRecords()) {
if(r instanceof FeatRecord) {
fr = (FeatRecord)r;
countFR++;
} else if (r.getSid() == FeatRecord.sid) {
fail("FeatRecord SID found but not created correctly!");
}
if(r instanceof FeatHdrRecord) {
countFRH++;
} else if (r.getSid() == FeatHdrRecord.sid) {
fail("FeatHdrRecord SID found but not created correctly!");
}
}
assertEquals(1, countFR);
assertEquals(1, countFRH);
assertNotNull(fr);
// Now check the contents are as expected
}
}

View File

@ -0,0 +1,33 @@
/* ====================================================================
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.usermodel;
import org.apache.poi.hssf.model.InternalWorkbook;
/**
* Helper class for HSSF tests that aren't within the
* HSSF UserModel package, but need to do internal
* UserModel things.
*/
public class HSSFTestHelper {
/**
* Lets non UserModel tests at the low level Workbook
*/
public static InternalWorkbook getWorkbookForTest(HSSFWorkbook wb) {
return wb.getWorkbook();
}
}

Binary file not shown.

Binary file not shown.