| /* ==================================================================== |
| 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.Map; |
| import java.util.function.Supplier; |
| import java.util.stream.Stream; |
| |
| import org.apache.logging.log4j.LogManager; |
| import org.apache.logging.log4j.Logger; |
| import org.apache.poi.hssf.record.common.FeatFormulaErr2; |
| import org.apache.poi.hssf.record.common.FeatProtection; |
| import org.apache.poi.hssf.record.common.FeatSmartTag; |
| import org.apache.poi.hssf.record.common.FtrHeader; |
| import org.apache.poi.hssf.record.common.SharedFeature; |
| import org.apache.poi.ss.util.CellRangeAddress; |
| import org.apache.poi.util.GenericRecordUtil; |
| import org.apache.poi.util.LittleEndianOutput; |
| |
| import static org.apache.logging.log4j.util.Unbox.box; |
| |
| /** |
| * Title: Feat (Feature) Record |
| * <P> |
| * This record specifies Shared Features data. It is normally paired |
| * up with a {@link FeatHdrRecord}. |
| */ |
| public final class FeatRecord extends StandardRecord { |
| private static final Logger LOG = LogManager.getLogger(FeatRecord.class); |
| public static final short sid = 0x0868; |
| // SIDs from newer versions |
| public static final short v11_sid = 0x0872; |
| public static final short v12_sid = 0x0878; |
| |
| private final FtrHeader futureHeader; |
| |
| /** See SHAREDFEATURES_* on {@link FeatHdrRecord} */ |
| private int isf_sharedFeatureType; |
| private byte reserved1; // Should always be zero |
| private long reserved2; // Should always be zero |
| /** Only matters if type is ISFFEC2 */ |
| private long cbFeatData; |
| private int reserved3; // Should always be zero |
| private CellRangeAddress[] cellRefs; |
| |
| /** |
| * Contents depends on isf_sharedFeatureType : |
| * ISFPROTECTION -> FeatProtection |
| * ISFFEC2 -> FeatFormulaErr2 |
| * ISFFACTOID -> FeatSmartTag |
| */ |
| private SharedFeature sharedFeature; |
| |
| public FeatRecord() { |
| futureHeader = new FtrHeader(); |
| futureHeader.setRecordType(sid); |
| } |
| |
| public FeatRecord(FeatRecord other) { |
| super(other); |
| futureHeader = other.futureHeader.copy(); |
| isf_sharedFeatureType = other.isf_sharedFeatureType; |
| reserved1 = other.reserved1; |
| reserved2 = other.reserved2; |
| cbFeatData = other.cbFeatData; |
| reserved3 = other.reserved3; |
| cellRefs = (other.cellRefs == null) ? null : |
| Stream.of(other.cellRefs).map(CellRangeAddress::copy).toArray(CellRangeAddress[]::new); |
| sharedFeature = (other.sharedFeature == null) ? null : other.sharedFeature.copy(); |
| } |
| |
| public FeatRecord(RecordInputStream in) { |
| futureHeader = new FtrHeader(in); |
| |
| isf_sharedFeatureType = in.readShort(); |
| reserved1 = in.readByte(); |
| reserved2 = in.readInt(); |
| int cref = in.readUShort(); |
| cbFeatData = in.readInt(); |
| reserved3 = in.readShort(); |
| |
| cellRefs = new CellRangeAddress[cref]; |
| for(int i=0; i<cellRefs.length; i++) { |
| cellRefs[i] = new CellRangeAddress(in); |
| } |
| |
| switch(isf_sharedFeatureType) { |
| case FeatHdrRecord.SHAREDFEATURES_ISFPROTECTION: |
| sharedFeature = new FeatProtection(in); |
| break; |
| case FeatHdrRecord.SHAREDFEATURES_ISFFEC2: |
| sharedFeature = new FeatFormulaErr2(in); |
| break; |
| case FeatHdrRecord.SHAREDFEATURES_ISFFACTOID: |
| sharedFeature = new FeatSmartTag(in); |
| break; |
| default: |
| LOG.atError().log("Unknown Shared Feature {} found!", box(isf_sharedFeatureType)); |
| } |
| } |
| |
| public short getSid() { |
| return sid; |
| } |
| |
| public void serialize(LittleEndianOutput out) { |
| futureHeader.serialize(out); |
| |
| out.writeShort(isf_sharedFeatureType); |
| out.writeByte(reserved1); |
| out.writeInt((int)reserved2); |
| out.writeShort(cellRefs.length); |
| out.writeInt((int)cbFeatData); |
| out.writeShort(reserved3); |
| |
| for (CellRangeAddress cellRef : cellRefs) { |
| cellRef.serialize(out); |
| } |
| |
| sharedFeature.serialize(out); |
| } |
| |
| protected int getDataSize() { |
| return 12 + 2+1+4+2+4+2+ |
| (cellRefs.length * CellRangeAddress.ENCODED_SIZE) |
| +sharedFeature.getDataSize(); |
| } |
| |
| public int getIsf_sharedFeatureType() { |
| return isf_sharedFeatureType; |
| } |
| |
| public long getCbFeatData() { |
| return cbFeatData; |
| } |
| public void setCbFeatData(long cbFeatData) { |
| this.cbFeatData = cbFeatData; |
| } |
| |
| public CellRangeAddress[] getCellRefs() { |
| return cellRefs; |
| } |
| public void setCellRefs(CellRangeAddress[] cellRefs) { |
| this.cellRefs = cellRefs; |
| } |
| |
| public SharedFeature getSharedFeature() { |
| return sharedFeature; |
| } |
| public void setSharedFeature(SharedFeature feature) { |
| this.sharedFeature = feature; |
| |
| if(feature instanceof FeatProtection) { |
| isf_sharedFeatureType = FeatHdrRecord.SHAREDFEATURES_ISFPROTECTION; |
| } |
| if(feature instanceof FeatFormulaErr2) { |
| isf_sharedFeatureType = FeatHdrRecord.SHAREDFEATURES_ISFFEC2; |
| } |
| if(feature instanceof FeatSmartTag) { |
| isf_sharedFeatureType = FeatHdrRecord.SHAREDFEATURES_ISFFACTOID; |
| } |
| |
| if(isf_sharedFeatureType == FeatHdrRecord.SHAREDFEATURES_ISFFEC2) { |
| cbFeatData = sharedFeature.getDataSize(); |
| } else { |
| cbFeatData = 0; |
| } |
| } |
| |
| @Override |
| public FeatRecord copy() { |
| return new FeatRecord(this); |
| } |
| |
| @Override |
| public HSSFRecordTypes getGenericRecordType() { |
| return HSSFRecordTypes.FEAT; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties( |
| "futureHeader", () -> futureHeader, |
| "isf_sharedFeatureType", this::getIsf_sharedFeatureType, |
| "reserved1", () -> reserved1, |
| "reserved2", () -> reserved2, |
| "cbFeatData", this::getCbFeatData, |
| "reserved3", () -> reserved3, |
| "cellRefs", this::getCellRefs, |
| "sharedFeature", this::getSharedFeature |
| ); |
| } |
| } |