Bläddra i källkod

fixed PageSettingsBlock to allow multiple HeaderFooterRecord records, see Bugzilla 48026

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@892467 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_7_BETA1
Yegor Kozlov 14 år sedan
förälder
incheckning
7a8bcc7b09

+ 3
- 0
src/documentation/content/xdocs/status.xml Visa fil



<changes> <changes>
<release version="3.7-SNAPSHOT" date="2010-??-??"> <release version="3.7-SNAPSHOT" date="2010-??-??">
<action dev="POI-DEVELOPERS" type="add">added Ant target to install artifacts in local repository </action>
<action dev="POI-DEVELOPERS" type="fix">48026 - fixed PageSettingsBlock to allow multiple HeaderFooterRecord records </action>
<action dev="POI-DEVELOPERS" type="fix">48202 - fixed CellRangeUtil.mergeCellRanges to work for adjacent cell regions </action>
<action dev="POI-DEVELOPERS" type="fix">48339 - fixed ExternalNameRecord to properly distinguish DDE data from OLE data items </action> <action dev="POI-DEVELOPERS" type="fix">48339 - fixed ExternalNameRecord to properly distinguish DDE data from OLE data items </action>
<action dev="POI-DEVELOPERS" type="fix">47920 - allow editing workbooks embedded into PowerPoint files</action> <action dev="POI-DEVELOPERS" type="fix">47920 - allow editing workbooks embedded into PowerPoint files</action>
<action dev="POI-DEVELOPERS" type="add">48343 - added implementation of SUBTOTAL function</action> <action dev="POI-DEVELOPERS" type="add">48343 - added implementation of SUBTOTAL function</action>

+ 3
- 0
src/java/org/apache/poi/hssf/model/Sheet.java Visa fil

// one or more PSB records found after some intervening non-PSB records // one or more PSB records found after some intervening non-PSB records
_psBlock.addLateRecords(rs); _psBlock.addLateRecords(rs);
} }
// YK: in some cases records can be moved to the preceding
// CustomViewSettingsRecordAggregate blocks
_psBlock.positionRecords(records);
continue; continue;
} }



+ 98
- 0
src/java/org/apache/poi/hssf/record/HeaderFooterRecord.java Visa fil

/* ====================================================================
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.record.aggregates.PageSettingsBlock;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;

import java.util.Arrays;

/**
* The HEADERFOOTER record stores information added in Office Excel 2007 for headers/footers.
*
* @author Yegor Kozlov
*/
public final class HeaderFooterRecord extends StandardRecord {

private static final byte[] BLANK_GUID = new byte[16];

public final static short sid = 0x089C;
private byte[] _rawData;

public HeaderFooterRecord(byte[] data) {
_rawData = data;
}

/**
* construct a HeaderFooterRecord record. No fields are interpreted and the record will
* be serialized in its original form more or less
* @param in the RecordInputstream to read the record from
*/
public HeaderFooterRecord(RecordInputStream in) {
_rawData = in.readRemainder();
}

/**
* spit the record out AS IS. no interpretation or identification
*/
public void serialize(LittleEndianOutput out) {
out.write(_rawData);
}

protected int getDataSize() {
return _rawData.length;
}
public short getSid()
{
return sid;
}

/**
* If this header belongs to a specific sheet view , the sheet view?s GUID will be saved here.
* <p>
* If it is zero, it means the current sheet. Otherwise, this field MUST match the guid field
* of the preceding {@link UserSViewBegin} record.
*
* @return the sheet view?s GUID
*/
public byte[] getGuid(){
byte[] guid = new byte[16];
System.arraycopy(_rawData, 12, guid, 0, guid.length);
return guid;
}

/**
* @return whether this record belongs to the current sheet
*/
public boolean isCurrentSheet(){
return Arrays.equals(getGuid(), BLANK_GUID);
}

public String toString() {
StringBuffer sb = new StringBuffer();

sb.append("[").append("HEADERFOOTER").append("] (0x");
sb.append(Integer.toHexString(sid).toUpperCase() + ")\n");
sb.append(" rawData=").append(HexDump.toHex(_rawData)).append("\n");
sb.append("[/").append("HEADERFOOTER").append("]\n");
return sb.toString();
}
}

+ 3
- 0
src/java/org/apache/poi/hssf/record/RecordFactory.java Visa fil

GutsRecord.class, GutsRecord.class,
HCenterRecord.class, HCenterRecord.class,
HeaderRecord.class, HeaderRecord.class,
HeaderFooterRecord.class,
HideObjRecord.class, HideObjRecord.class,
HorizontalPageBreakRecord.class, HorizontalPageBreakRecord.class,
HyperlinkRecord.class, HyperlinkRecord.class,
TopMarginRecord.class, TopMarginRecord.class,
UncalcedRecord.class, UncalcedRecord.class,
UseSelFSRecord.class, UseSelFSRecord.class,
UserSViewBegin.class,
UserSViewEnd.class,
VCenterRecord.class, VCenterRecord.class,
VerticalPageBreakRecord.class, VerticalPageBreakRecord.class,
WindowOneRecord.class, WindowOneRecord.class,

+ 0
- 4
src/java/org/apache/poi/hssf/record/UnknownRecord.java Visa fil

public static final int BITMAP_00E9 = 0x00E9; public static final int BITMAP_00E9 = 0x00E9;
public static final int PHONETICPR_00EF = 0x00EF; public static final int PHONETICPR_00EF = 0x00EF;
public static final int LABELRANGES_015F = 0x015F; public static final int LABELRANGES_015F = 0x015F;
public static final int USERSVIEWBEGIN_01AA = 0x01AA;
public static final int USERSVIEWEND_01AB = 0x01AB;
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;
case LABELRANGES_015F: return "LABELRANGES"; case LABELRANGES_015F: return "LABELRANGES";
case 0x01BA: return "CODENAME"; case 0x01BA: return "CODENAME";
case 0x01A9: return "USERBVIEW"; case 0x01A9: return "USERBVIEW";
case USERSVIEWBEGIN_01AA: return "USERSVIEWBEGIN";
case USERSVIEWEND_01AB: return "USERSVIEWEND";
case 0x01AD: return "QSI"; case 0x01AD: return "QSI";


case 0x01C0: return "EXCEL9FILE"; case 0x01C0: return "EXCEL9FILE";

+ 87
- 0
src/java/org/apache/poi/hssf/record/UserSViewBegin.java Visa fil

/* ====================================================================
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.record.aggregates.PageSettingsBlock;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;

import java.util.Arrays;

/**
* The UserSViewBegin record specifies settings for a custom view associated with the sheet.
* This record also marks the start of custom view records, which save custom view settings.
* Records between {@link UserSViewBegin} and {@link UserSViewEnd} contain settings for the custom view,
* not settings for the sheet itself.
*
* @author Yegor Kozlov
*/
public final class UserSViewBegin extends StandardRecord {

public final static short sid = 0x01AA;
private byte[] _rawData;

public UserSViewBegin(byte[] data) {
_rawData = data;
}

/**
* construct an UserSViewBegin record. No fields are interpreted and the record will
* be serialized in its original form more or less
* @param in the RecordInputstream to read the record from
*/
public UserSViewBegin(RecordInputStream in) {
_rawData = in.readRemainder();
}

/**
* spit the record out AS IS. no interpretation or identification
*/
public void serialize(LittleEndianOutput out) {
out.write(_rawData);
}

protected int getDataSize() {
return _rawData.length;
}

public short getSid()
{
return sid;
}

/**
* @return Globally unique identifier for the custom view
*/
public byte[] getGuid(){
byte[] guid = new byte[16];
System.arraycopy(_rawData, 0, guid, 0, guid.length);
return guid;
}

public String toString() {
StringBuffer sb = new StringBuffer();

sb.append("[").append("USERSVIEWBEGIN").append("] (0x");
sb.append(Integer.toHexString(sid).toUpperCase() + ")\n");
sb.append(" rawData=").append(HexDump.toHex(_rawData)).append("\n");
sb.append("[/").append("USERSVIEWBEGIN").append("]\n");
return sb.toString();
}
}

+ 75
- 0
src/java/org/apache/poi/hssf/record/UserSViewEnd.java Visa fil

/* ====================================================================
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.record.aggregates.PageSettingsBlock;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;

import java.util.Arrays;

/**
* The UserSViewEnd record marks the end of the settings for a custom view associated with the sheet
*
* @author Yegor Kozlov
*/
public final class UserSViewEnd extends StandardRecord {

public final static short sid = 0x01AB;
private byte[] _rawData;

public UserSViewEnd(byte[] data) {
_rawData = data;
}

/**
* construct an UserSViewEnd record. No fields are interpreted and the record will
* be serialized in its original form more or less
* @param in the RecordInputstream to read the record from
*/
public UserSViewEnd(RecordInputStream in) {
_rawData = in.readRemainder();
}

/**
* spit the record out AS IS. no interpretation or identification
*/
public void serialize(LittleEndianOutput out) {
out.write(_rawData);
}

protected int getDataSize() {
return _rawData.length;
}

public short getSid()
{
return sid;
}

public String toString() {
StringBuffer sb = new StringBuffer();

sb.append("[").append("USERSVIEWEND").append("] (0x");
sb.append(Integer.toHexString(sid).toUpperCase() + ")\n");
sb.append(" rawData=").append(HexDump.toHex(_rawData)).append("\n");
sb.append("[/").append("USERSVIEWEND").append("]\n");
return sb.toString();
}

}

+ 3
- 7
src/java/org/apache/poi/hssf/record/aggregates/ChartSubstreamRecordAggregate.java Visa fil

import java.util.List; import java.util.List;


import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.*;


/** /**
* Manages the all the records associated with a chart sub-stream.<br/> * Manages the all the records associated with a chart sub-stream.<br/>
while (rs.peekNextClass() != EOFRecord.class) { while (rs.peekNextClass() != EOFRecord.class) {
if (PageSettingsBlock.isComponentRecord(rs.peekNextSid())) { if (PageSettingsBlock.isComponentRecord(rs.peekNextSid())) {
if (_psBlock != null) { if (_psBlock != null) {
if (rs.peekNextSid() == UnknownRecord.HEADER_FOOTER_089C) {
if (rs.peekNextSid() == HeaderFooterRecord.sid) {
// test samples: 45538_classic_Footer.xls, 45538_classic_Header.xls // test samples: 45538_classic_Footer.xls, 45538_classic_Header.xls
_psBlock.addLateHeaderFooter(rs.getNext());
_psBlock.addLateHeaderFooter((HeaderFooterRecord)rs.getNext());
continue; continue;
} }
throw new IllegalStateException( throw new IllegalStateException(

+ 9
- 7
src/java/org/apache/poi/hssf/record/aggregates/CustomViewSettingsRecordAggregate.java Visa fil

import java.util.List; import java.util.List;


import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.*;


/** /**
* Manages the all the records associated with a 'Custom View Settings' sub-stream.<br/> * Manages the all the records associated with a 'Custom View Settings' sub-stream.<br/>


public CustomViewSettingsRecordAggregate(RecordStream rs) { public CustomViewSettingsRecordAggregate(RecordStream rs) {
_begin = rs.getNext(); _begin = rs.getNext();
if (_begin.getSid() != UnknownRecord.USERSVIEWBEGIN_01AA) {
if (_begin.getSid() != UserSViewBegin.sid) {
throw new IllegalStateException("Bad begin record"); throw new IllegalStateException("Bad begin record");
} }
List<RecordBase> temp = new ArrayList<RecordBase>(); List<RecordBase> temp = new ArrayList<RecordBase>();
while (rs.peekNextSid() != UnknownRecord.USERSVIEWEND_01AB) {
while (rs.peekNextSid() != UserSViewEnd.sid) {
if (PageSettingsBlock.isComponentRecord(rs.peekNextSid())) { if (PageSettingsBlock.isComponentRecord(rs.peekNextSid())) {
if (_psBlock != null) { if (_psBlock != null) {
throw new IllegalStateException( throw new IllegalStateException(
} }
_recs = temp; _recs = temp;
_end = rs.getNext(); // no need to save EOF in field _end = rs.getNext(); // no need to save EOF in field
if (_end.getSid() != UnknownRecord.USERSVIEWEND_01AB) {
if (_end.getSid() != UserSViewEnd.sid) {
throw new IllegalStateException("Bad custom view settings end record"); throw new IllegalStateException("Bad custom view settings end record");
} }
} }
} }


public static boolean isBeginRecord(int sid) { public static boolean isBeginRecord(int sid) {
return sid == UnknownRecord.USERSVIEWBEGIN_01AA;
return sid == UserSViewBegin.sid;
} }

public void append(RecordBase r){
_recs.add(r);
}
} }

+ 58
- 27
src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java Visa fil

import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Arrays;


import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.BottomMarginRecord;
import org.apache.poi.hssf.record.ContinueRecord;
import org.apache.poi.hssf.record.FooterRecord;
import org.apache.poi.hssf.record.HCenterRecord;
import org.apache.poi.hssf.record.HeaderRecord;
import org.apache.poi.hssf.record.HorizontalPageBreakRecord;
import org.apache.poi.hssf.record.LeftMarginRecord;
import org.apache.poi.hssf.record.Margin;
import org.apache.poi.hssf.record.PageBreakRecord;
import org.apache.poi.hssf.record.PrintSetupRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RightMarginRecord;
import org.apache.poi.hssf.record.TopMarginRecord;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.VerticalPageBreakRecord;
import org.apache.poi.hssf.record.*;


/** /**
* Groups the page settings records for a worksheet.<p/> * Groups the page settings records for a worksheet.<p/>
private final List<PLSAggregate> _plsRecords; private final List<PLSAggregate> _plsRecords;
private PrintSetupRecord _printSetup; private PrintSetupRecord _printSetup;
private Record _bitmap; private Record _bitmap;
private Record _headerFooter;
private Record _printSize;
private HeaderFooterRecord _headerFooter;
/**
* HeaderFooterRecord records belonging to preceding CustomViewSettingsRecordAggregates.
* The indicator of such records is a non-zero GUID,
* see {@link org.apache.poi.hssf.record.HeaderFooterRecord#getGuid()}
*/
private List<HeaderFooterRecord> _sviewHeaderFooters = new ArrayList<HeaderFooterRecord>();
private Record _printSize;


public PageSettingsBlock(RecordStream rs) { public PageSettingsBlock(RecordStream rs) {
_plsRecords = new ArrayList<PLSAggregate>(); _plsRecords = new ArrayList<PLSAggregate>();
_hCenter = createHCenter(); _hCenter = createHCenter();
_vCenter = createVCenter(); _vCenter = createVCenter();
_printSetup = createPrintSetup(); _printSetup = createPrintSetup();
}
}


/** /**
* @return <code>true</code> if the specified Record sid is one belonging to the * @return <code>true</code> if the specified Record sid is one belonging to the
case PrintSetupRecord.sid: case PrintSetupRecord.sid:
case UnknownRecord.BITMAP_00E9: case UnknownRecord.BITMAP_00E9:
case UnknownRecord.PRINTSIZE_0033: case UnknownRecord.PRINTSIZE_0033:
case UnknownRecord.HEADER_FOOTER_089C: // extra header/footer settings supported by Excel 2007
case HeaderFooterRecord.sid: // extra header/footer settings supported by Excel 2007
return true; return true;
} }
return false; return false;
checkNotPresent(_printSize); checkNotPresent(_printSize);
_printSize = rs.getNext(); _printSize = rs.getNext();
break; break;
case UnknownRecord.HEADER_FOOTER_089C:
checkNotPresent(_headerFooter);
_headerFooter = rs.getNext();
break;
case HeaderFooterRecord.sid:
//there can be multiple HeaderFooterRecord records belonging to different sheet views
HeaderFooterRecord hf = (HeaderFooterRecord)rs.getNext();
if(hf.isCurrentSheet()) _headerFooter = hf;
else {
_sviewHeaderFooters.add(hf);
}
break;
default: default:
// all other record types are not part of the PageSettingsBlock // all other record types are not part of the PageSettingsBlock
return false; return false;
* HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after * HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after
* the {@link PageSettingsBlock} where it belongs. * the {@link PageSettingsBlock} where it belongs.
*/ */
public void addLateHeaderFooter(Record rec) {
public void addLateHeaderFooter(HeaderFooterRecord rec) {
if (_headerFooter != null) { if (_headerFooter != null) {
throw new IllegalStateException("This page settings block already has a header/footer record"); throw new IllegalStateException("This page settings block already has a header/footer record");
} }
if (rec.getSid() != UnknownRecord.HEADER_FOOTER_089C) {
if (rec.getSid() != HeaderFooterRecord.sid) {
throw new RecordFormatException("Unexpected header-footer record sid: 0x" + Integer.toHexString(rec.getSid())); throw new RecordFormatException("Unexpected header-footer record sid: 0x" + Integer.toHexString(rec.getSid()));
} }
_headerFooter = rec; _headerFooter = rec;
} }
} }
} }

/**
* Some apps can define multiple HeaderFooterRecord records for a sheet.
* When saving such a file Excel 2007 re-positiones them according to the followig rules:
* - take a HeaderFooterRecord and read 16-byte GUID at offset 12. If it is zero,
* it means the current sheet and the given HeaderFooterRecord belongs to this PageSettingsBlock
* - If GUID is not zero then search in preceding CustomViewSettingsRecordAggregates.
* Compare first 16 bytes of UserSViewBegin with the HeaderFooterRecord's GUID. If match,
* then append the HeaderFooterRecord to this CustomViewSettingsRecordAggregates
*
* @param sheetRecords the list of sheet records read so far
*/
public void positionRecords(List<RecordBase> sheetRecords) {
// loop through HeaderFooterRecord records having not-empty GUID and match them with
// CustomViewSettingsRecordAggregate blocks having UserSViewBegin with the same GUID
for (final Iterator<HeaderFooterRecord> it = _sviewHeaderFooters.iterator(); it.hasNext(); ) {
final HeaderFooterRecord hf = it.next();
for (RecordBase rb : sheetRecords) {
if (rb instanceof CustomViewSettingsRecordAggregate) {
final CustomViewSettingsRecordAggregate cv = (CustomViewSettingsRecordAggregate) rb;
cv.visitContainedRecords(new RecordVisitor() {
public void visitRecord(Record r) {
if (r.getSid() == UserSViewBegin.sid) {
byte[] guid1 = ((UserSViewBegin) r).getGuid();
byte[] guid2 = hf.getGuid();
if (Arrays.equals(guid1, guid2)) {
cv.append(hf);
it.remove();
}
}
}
});
}
}
}
}
} }

+ 84
- 21
src/testcases/org/apache/poi/hssf/record/aggregates/TestPageSettingsBlock.java Visa fil

import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BottomMarginRecord;
import org.apache.poi.hssf.record.ContinueRecord;
import org.apache.poi.hssf.record.DimensionsRecord;
import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.FooterRecord;
import org.apache.poi.hssf.record.HCenterRecord;
import org.apache.poi.hssf.record.HeaderRecord;
import org.apache.poi.hssf.record.IndexRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.HSSFPrintSetup; import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
BOFRecord.createSheetBOF(), BOFRecord.createSheetBOF(),
new HeaderRecord("&LSales Figures"), new HeaderRecord("&LSales Figures"),
new FooterRecord("&LJanuary"), new FooterRecord("&LJanuary"),
ur(UnknownRecord.HEADER_FOOTER_089C, "9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00"),
new HeaderFooterRecord(HexRead.readFromString("9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00")),
new DimensionsRecord(), new DimensionsRecord(),
new WindowTwoRecord(), new WindowTwoRecord(),
ur(UnknownRecord.USERSVIEWBEGIN_01AA, "ED 77 3B 86 BC 3F 37 4C A9 58 60 23 43 68 54 4B 01 00 00 00 64 00 00 00 40 00 00 00 02 00 00 00 3D 80 04 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F FF FF 01 00"),
new UserSViewBegin(HexRead.readFromString("ED 77 3B 86 BC 3F 37 4C A9 58 60 23 43 68 54 4B 01 00 00 00 64 00 00 00 40 00 00 00 02 00 00 00 3D 80 04 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F FF FF 01 00")),
new HeaderRecord("&LSales Figures"), new HeaderRecord("&LSales Figures"),
new FooterRecord("&LJanuary"), new FooterRecord("&LJanuary"),
ur(UnknownRecord.HEADER_FOOTER_089C, "9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00"),
ur(UnknownRecord.USERSVIEWEND_01AB, "01, 00"),
new HeaderFooterRecord(HexRead.readFromString("9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00")),
new UserSViewEnd(HexRead.readFromString("01, 00")),


EOFRecord.instance, EOFRecord.instance,
}; };
new FooterRecord("&LJanuary"), new FooterRecord("&LJanuary"),
new DimensionsRecord(), new DimensionsRecord(),
new WindowTwoRecord(), new WindowTwoRecord(),
ur(UnknownRecord.HEADER_FOOTER_089C, "9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00"),
new HeaderFooterRecord(HexRead.readFromString("9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00")),
EOFRecord.instance, EOFRecord.instance,
}; };
RecordStream rs = new RecordStream(Arrays.asList(recs), 0); RecordStream rs = new RecordStream(Arrays.asList(recs), 0);
assertEquals(IndexRecord.class, outRecs[1].getClass()); assertEquals(IndexRecord.class, outRecs[1].getClass());
assertEquals(HeaderRecord.class, outRecs[2].getClass()); assertEquals(HeaderRecord.class, outRecs[2].getClass());
assertEquals(FooterRecord.class, outRecs[3].getClass()); assertEquals(FooterRecord.class, outRecs[3].getClass());
assertEquals(UnknownRecord.HEADER_FOOTER_089C, outRecs[4].getSid());
assertEquals(HeaderFooterRecord.class, outRecs[4].getClass());
assertEquals(DimensionsRecord.class, outRecs[5].getClass()); assertEquals(DimensionsRecord.class, outRecs[5].getClass());
assertEquals(WindowTwoRecord.class, outRecs[6].getClass()); assertEquals(WindowTwoRecord.class, outRecs[6].getClass());
assertEquals(EOFRecord.instance, outRecs[7]); assertEquals(EOFRecord.instance, outRecs[7]);
// records were assembled in standard order, so this simple check is OK // records were assembled in standard order, so this simple check is OK
assertTrue(Arrays.equals(recs, outRecs)); assertTrue(Arrays.equals(recs, outRecs));
} }

public void testDuplicateHeaderFooter_bug48026() {

Record[] recs = {
BOFRecord.createSheetBOF(),
new IndexRecord(),

//PageSettingsBlock
new HeaderRecord("&LDecember"),
new FooterRecord("&LJanuary"),
new DimensionsRecord(),

new WindowTwoRecord(),

//CustomViewSettingsRecordAggregate
new UserSViewBegin(HexRead.readFromString("53 CE BD CC DE 38 44 45 97 C1 5C 89 F9 37 32 1B 01 00 00 00 64 00 00 00 40 00 00 00 03 00 00 00 7D 00 00 20 00 00 34 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF")),
new SelectionRecord(0, 0),
new UserSViewEnd(HexRead.readFromString("01 00")),

// two HeaderFooterRecord records, the first one has zero GUID (16 bytes at offset 12) and belongs to the PSB,
// the other is matched with a CustomViewSettingsRecordAggregate having UserSViewBegin with the same GUID
new HeaderFooterRecord(HexRead.readFromString("9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 33 00 00 00 00 00 00 00 00")),
new HeaderFooterRecord(HexRead.readFromString("9C 08 00 00 00 00 00 00 00 00 00 00 53 CE BD CC DE 38 44 45 97 C1 5C 89 F9 37 32 1B 34 33 00 00 00 00 00 00 00 00")),

EOFRecord.instance,
};
RecordStream rs = new RecordStream(Arrays.asList(recs), 0);
Sheet sheet;
try {
sheet = Sheet.createSheet(rs);
} catch (RuntimeException e) {
if (e.getMessage().equals("Duplicate PageSettingsBlock record (sid=0x89c)")) {
throw new AssertionFailedError("Identified bug 48026");
}
throw e;
}

RecordCollector rv = new RecordCollector();
sheet.visitContainedRecords(rv, 0);
Record[] outRecs = rv.getRecords();

assertEquals(recs.length, outRecs.length);
//expected order of records:
Record[] expectedRecs = {
recs[0], //BOFRecord
recs[1], //IndexRecord

//PageSettingsBlock
recs[2], //HeaderRecord
recs[3], //FooterRecord
recs[9], //HeaderFooterRecord
recs[4], // DimensionsRecord
recs[5], // WindowTwoRecord

//CustomViewSettingsRecordAggregate
recs[6], // UserSViewBegin
recs[7], // SelectionRecord
recs[10], // HeaderFooterRecord
recs[8], // UserSViewEnd

recs[11], //EOFRecord
};
for(int i=0; i < expectedRecs.length; i++){
assertEquals("Record mismatch at index " + i, expectedRecs[i].getClass(), outRecs[i].getClass());
}
HeaderFooterRecord hd1 = (HeaderFooterRecord)expectedRecs[4];
//GUID is zero
assertTrue(Arrays.equals(new byte[16], hd1.getGuid()));
assertTrue(hd1.isCurrentSheet());

UserSViewBegin svb = (UserSViewBegin)expectedRecs[7];
HeaderFooterRecord hd2 = (HeaderFooterRecord)expectedRecs[9];
assertFalse(hd2.isCurrentSheet());
//GUIDs of HeaderFooterRecord and UserSViewBegin must be the same
assertTrue(Arrays.equals(svb.getGuid(), hd2.getGuid()));
}

} }

Laddar…
Avbryt
Spara