/********************************************************************* * * Copyright (C) 2002 Andrew Khan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***************************************************************************/ package jxl.biff; import common.Logger; import jxl.read.biff.Record; /** * Extension of the standard RecordData which is used to support those * records which, once read, may also be written */ public abstract class WritableRecordData extends RecordData implements ByteData { /** * The logger */ private static Logger logger = Logger.getLogger(WritableRecordData.class); /** * The maximum length allowed by Excel for any record length */ protected static final int maxRecordLength = 8228; /** * Constructor used by the writable records * * @param t the biff type of this record */ protected WritableRecordData(Type t) { super(t); } /** * Constructor used when reading a record * * @param t the raw data read from the biff file */ protected WritableRecordData(Record t) { super(t); } /** * Used when writing out records. This portion of the method handles the * biff code and the length of the record and appends on the data retrieved * from the subclasses * * @return the full record data to be written out to the compound file */ public final byte[] getBytes() { byte[] data = getData(); int dataLength = data.length; // Don't the call the automatic continuation code for now // Assert.verify(dataLength <= maxRecordLength - 4); // If the bytes length is greater than the max record length // then split out the data set into continue records if (data.length > maxRecordLength - 4) { dataLength = maxRecordLength - 4; data = handleContinueRecords(data); } byte[] bytes = new byte[data.length + 4]; System.arraycopy(data, 0, bytes, 4, data.length); IntegerHelper.getTwoBytes(getCode(), bytes, 0); IntegerHelper.getTwoBytes(dataLength, bytes, 2); return bytes; } /** * The number of bytes for this record exceeds the maximum record * length, so a continue is required * @param data the raw data * @return the continued data */ private byte[] handleContinueRecords(byte[] data) { // Deduce the number of continue records int continuedData = data.length - (maxRecordLength - 4); int numContinueRecords = continuedData / (maxRecordLength - 4) + 1; // Create the new byte array, allowing for the continue records // code and length byte[] newdata = new byte[data.length + numContinueRecords * 4]; // Copy the bona fide record data into the beginning of the super // record System.arraycopy(data, 0, newdata, 0, maxRecordLength - 4); int oldarraypos = maxRecordLength - 4; int newarraypos = maxRecordLength - 4; // Now handle all the continue records for (int i = 0; i < numContinueRecords; i++) { // The number of bytes to add into the new array int length = Math.min(data.length - oldarraypos, maxRecordLength - 4); // Add in the continue record code IntegerHelper.getTwoBytes(Type.CONTINUE.value, newdata, newarraypos); IntegerHelper.getTwoBytes(length, newdata, newarraypos + 2); // Copy in as much of the new data as possible System.arraycopy(data, oldarraypos, newdata, newarraypos + 4, length); // Update the position counters oldarraypos += length; newarraypos += length + 4; } return newdata; } /** * Abstract method called by the getBytes method. Subclasses implement * this method to incorporate their specific binary data - excluding the * biff code and record length, which is handled by this class * * @return subclass specific biff data */ protected abstract byte[] getData(); }