-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.contrib.poibrowser;
-import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
throw new RuntimeException(t.getMessage());
}
- try
- {
- is.close();
- }
- catch (IOException ex)
- {
- System.err.println
- ("Unexpected exception while closing " +
- event.getName() + " in " + event.getPath().toString());
- ex.printStackTrace(System.err);
- }
+ is.close();
final MutableTreeNode parentNode = getNode(d.path, filename, rootNode);
final MutableTreeNode nameNode = new DefaultMutableTreeNode(d.name);
if(r instanceof ExtendedFormatRecord) {
} else if(r instanceof StyleRecord) {
StyleRecord sr = (StyleRecord)r;
- if(sr.getIndex() == xfIndex) {
+ if(sr.getXFIndex() == xfIndex) {
return sr;
}
} else {
// Style records always follow after
// the ExtendedFormat records
StyleRecord newSR = new StyleRecord();
- newSR.setIndex((short)xfIndex);
+ newSR.setXFIndex(xfIndex);
// Find the spot
int addAt = -1;
* @see org.apache.poi.hssf.record.StyleRecord
* @see org.apache.poi.hssf.record.Record
*/
-
protected Record createStyle(int id) { // we'll need multiple editions
StyleRecord retval = new StyleRecord();
switch (id) {
case 0 :
- retval.setIndex(( short ) 0xffff8010);
- retval.setBuiltin(( byte ) 3);
+ retval.setXFIndex(0x010);
+ retval.setBuiltinStyle(3);
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
break;
case 1 :
- retval.setIndex(( short ) 0xffff8011);
- retval.setBuiltin(( byte ) 6);
+ retval.setXFIndex(0x011);
+ retval.setBuiltinStyle(6);
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
break;
case 2 :
- retval.setIndex(( short ) 0xffff8012);
- retval.setBuiltin(( byte ) 4);
+ retval.setXFIndex(0x012);
+ retval.setBuiltinStyle(4);
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
break;
case 3 :
- retval.setIndex(( short ) 0xffff8013);
- retval.setBuiltin(( byte ) 7);
+ retval.setXFIndex(0x013);
+ retval.setBuiltinStyle(7);
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
break;
case 4 :
- retval.setIndex(( short ) 0xffff8000);
- retval.setBuiltin(( byte ) 0);
+ retval.setXFIndex(0x000);
+ retval.setBuiltinStyle(0);
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
break;
case 5 :
- retval.setIndex(( short ) 0xffff8014);
- retval.setBuiltin(( byte ) 5);
+ retval.setXFIndex(0x014);
+ retval.setBuiltinStyle(5);
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
break;
}
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.constant.ConstantValueParser;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
/**
- * Title: CRN <P>
- * Description: This record stores the contents of an external cell or cell range <P>
- * REFERENCE: 5.23<P>
+ * Title: CRN(0x005A) <p/>
+ * Description: This record stores the contents of an external cell or cell range <p/>
+ * REFERENCE: OOO 5.23<p/>
*
* @author josh micich
*/
public final class CRNRecord extends Record {
- public final static short sid = 0x5A;
+ public final static short sid = 0x005A;
private int field_1_last_column_index;
private int field_2_first_column_index;
public CRNRecord(RecordInputStream in) {
- field_1_last_column_index = in.readByte() & 0x00FF;
- field_2_first_column_index = in.readByte() & 0x00FF;
+ field_1_last_column_index = in.readUByte();
+ field_2_first_column_index = in.readUByte();
field_3_row_index = in.readShort();
int nValues = field_1_last_column_index - field_2_first_column_index + 1;
field_4_constant_values = ConstantValueParser.parse(in, nValues);
public int serialize(int offset, byte [] data) {
int dataSize = getDataSize();
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putShort(data, 2 + offset, (short) dataSize);
- LittleEndian.putByte(data, 4 + offset, field_1_last_column_index);
- LittleEndian.putByte(data, 5 + offset, field_2_first_column_index);
- LittleEndian.putShort(data, 6 + offset, (short) field_3_row_index);
- ConstantValueParser.encode(data, 8 + offset, field_4_constant_values);
- return getRecordSize();
+ int recSize = 4 + dataSize;
+ LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
+ out.writeShort(sid);
+ out.writeShort(dataSize);
+ out.writeByte(field_1_last_column_index);
+ out.writeByte(field_2_first_column_index);
+ out.writeShort(field_3_row_index);
+ ConstantValueParser.encode(out, field_4_constant_values);
+ return recSize;
}
public int getRecordSize() {
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
field_3_unicode_flag = ( in.readByte() & 0x01 ) != 0;
remaining -= LittleEndian.BYTE_SIZE;
if (field_3_unicode_flag) {
- field_4_ole_classname = in.readUnicodeLEString(nChars);
+ field_4_ole_classname = StringUtil.readUnicodeLE(in, nChars);
stringByteCount = nChars * 2;
} else {
- field_4_ole_classname = in.readCompressedUnicode(nChars);
+ field_4_ole_classname = StringUtil.readCompressedUnicode(in, nChars);
stringByteCount = nChars;
}
} else {
}
private static Ptg readRefPtg(byte[] formulaRawBytes) {
- byte[] data = new byte[formulaRawBytes.length + 4];
- LittleEndian.putUShort(data, 0, -5555);
- LittleEndian.putUShort(data, 2, formulaRawBytes.length);
- System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
- RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
- in.nextRecord();
+ LittleEndianInput in = new LittleEndianInputStream(new ByteArrayInputStream(formulaRawBytes));
byte ptgSid = in.readByte();
switch(ptgSid) {
case AreaPtg.sid: return new AreaPtg(in);
.append( "=" )
.append(ptg.toString() )
.append( "\n" )
- .append(ptg.toDebugString() )
+ .append(ptg.toString())
.append( "\n" );
}
}
package org.apache.poi.hssf.record;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianInput;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInputStream;
/**
* Title: Record Input Stream<P>
/** Maximum size of a single record (minus the 4 byte header) without a continue*/
public final static short MAX_RECORD_DATA_SIZE = 8224;
private static final int INVALID_SID_VALUE = -1;
+ /**
+ * When {@link #_currentDataLength} has this value, it means that the previous BIFF record is
+ * finished, the next sid has been properly read, but the data size field has not been read yet.
+ */
+ private static final int DATA_LEN_NEEDS_TO_BE_READ = -1;
+ private static final byte[] EMPTY_BYTE_ARRAY = { };
+
+ /** {@link LittleEndianInput} facet of the wrapped {@link InputStream} */
+ private final LittleEndianInput _le;
+ /** the record identifier of the BIFF record currently being read */
+ private int _currentSid;
+ /**
+ * Length of the data section of the current BIFF record (always 4 less than the total record size).
+ * When uninitialised, this field is set to {@link #DATA_LEN_NEEDS_TO_BE_READ}.
+ */
+ private int _currentDataLength;
+ /**
+ * The BIFF record identifier for the next record is read when just as the current record
+ * is finished.
+ * This field is only really valid during the time that ({@link #_currentDataLength} ==
+ * {@link #DATA_LEN_NEEDS_TO_BE_READ}). At most other times its value is not really the
+ * 'sid of the next record'. Wwhile mid-record, this field coincidentally holds the sid
+ * of the current record.
+ */
+ private int _nextSid;
+ /**
+ * index within the data section of the current BIFF record
+ */
+ private int _currentDataOffset;
+
+ public RecordInputStream(InputStream in) throws RecordFormatException {
+ if (in instanceof LittleEndianInput) {
+ // accessing directly is an optimisation
+ _le = (LittleEndianInput) in;
+ } else {
+ // less optimal, but should work OK just the same. Often occurs in junit tests.
+ _le = new LittleEndianInputStream(in);
+ }
+ _nextSid = readNextSid();
+ }
+
+ /**
+ * @returns the number of bytes available in the current BIFF record
+ * @see #remaining()
+ */
+ public int available() {
+ return remaining();
+ }
- private InputStream in;
- private short currentSid;
- private short currentLength = -1;
- private short nextSid;
-
- private final byte[] data = new byte[MAX_RECORD_DATA_SIZE];
- private short recordOffset;
- private long pos;
-
- private boolean autoContinue = true;
-
- public RecordInputStream(InputStream in) throws RecordFormatException {
- this.in = in;
- try {
- nextSid = LittleEndian.readShort(in);
- //Don't increment the pos just yet (technically we are at the start of
- //the record stream until nextRecord is called).
- } catch (IOException ex) {
- throw new RecordFormatException("Error reading bytes", ex);
- }
- }
-
- /** This method will read a byte from the current record*/
public int read() {
checkRecordPosition(LittleEndian.BYTE_SIZE);
-
- byte result = data[recordOffset];
- recordOffset += LittleEndian.BYTE_SIZE;
- pos += LittleEndian.BYTE_SIZE;
- return result;
+ _currentDataOffset += LittleEndian.BYTE_SIZE;
+ return _le.readUByte();
+ }
+ public int read(byte[] b, int off, int len) {
+ int limit = Math.min(len, remaining());
+ if (limit == 0) {
+ return 0;
+ }
+ readFully(b, off,limit);
+ return limit;
}
- public short getSid() {
- return currentSid;
- }
-
- public short getLength() {
- return currentLength;
- }
-
- public short getRecordOffset() {
- return recordOffset;
- }
-
- public long getPos() {
- return pos;
- }
-
- public boolean hasNextRecord() {
- return nextSid != INVALID_SID_VALUE;
- }
+ public short getSid() {
+ return (short) _currentSid;
+ }
- /** Moves to the next record in the stream.
- *
- * <i>Note: The auto continue flag is reset to true</i>
- */
- public void nextRecord() throws RecordFormatException {
- if ((currentLength != -1) && (currentLength != recordOffset)) {
- System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(currentSid));
- }
- currentSid = nextSid;
- pos += LittleEndian.SHORT_SIZE;
- autoContinue = true;
- try {
- recordOffset = 0;
- currentLength = LittleEndian.readShort(in);
- if (currentLength > MAX_RECORD_DATA_SIZE)
- throw new RecordFormatException("The content of an excel record cannot exceed "+MAX_RECORD_DATA_SIZE+" bytes");
- pos += LittleEndian.SHORT_SIZE;
- in.read(data, 0, currentLength);
-
- //Read the Sid of the next record
- if (in.available() < EOFRecord.ENCODED_SIZE) {
- if (in.available() > 0) {
- // some scrap left over?
- // ex45582-22397.xls has one extra byte after the last record
- // Excel reads that file OK
- }
- nextSid = INVALID_SID_VALUE;
- } else {
- nextSid = LittleEndian.readShort(in);
- if (nextSid == INVALID_SID_VALUE) {
- throw new RecordFormatException("Found sid " + nextSid + " after record with sid 0x"
- + Integer.toHexString(currentSid).toUpperCase());
- }
- }
- } catch (IOException ex) {
- throw new RecordFormatException("Error reading bytes", ex);
- }
- }
+ /**
+ * Note - this method is expected to be called only when completed reading the current BIFF record.
+ * Calling this before reaching the end of the current record will cause all remaining data to be
+ * discarded
+ */
+ public boolean hasNextRecord() {
+ if (_currentDataLength != -1 && _currentDataLength != _currentDataOffset) {
+ System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(_currentSid));
+ // discard unread data
+ while (_currentDataOffset < _currentDataLength) {
+ readByte();
+ }
+ }
+ if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
+ _nextSid = readNextSid();
+ }
+ return _nextSid != INVALID_SID_VALUE;
+ }
- public void setAutoContinue(boolean enable) {
- this.autoContinue = enable;
- }
+ /**
+ *
+ * @return the sid of the next record or {@link #INVALID_SID_VALUE} if at end of stream
+ */
+ private int readNextSid() {
+ int nAvailable = _le.available();
+ if (nAvailable < EOFRecord.ENCODED_SIZE) {
+ if (nAvailable > 0) {
+ // some scrap left over?
+ // ex45582-22397.xls has one extra byte after the last record
+ // Excel reads that file OK
+ }
+ return INVALID_SID_VALUE;
+ }
+ int result = _le.readUShort();
+ if (result == INVALID_SID_VALUE) {
+ throw new RecordFormatException("Found invalid sid (" + result + ")");
+ }
+ _currentDataLength = DATA_LEN_NEEDS_TO_BE_READ;
+ return result;
+ }
- public boolean getAutoContinue() {
- return autoContinue;
- }
+ /** Moves to the next record in the stream.
+ *
+ * <i>Note: The auto continue flag is reset to true</i>
+ */
+ public void nextRecord() throws RecordFormatException {
+ if (_nextSid == INVALID_SID_VALUE) {
+ throw new IllegalStateException("EOF - next record not available");
+ }
+ if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
+ throw new IllegalStateException("Cannot call nextRecord() without checking hasNextRecord() first");
+ }
+ _currentSid = _nextSid;
+ _currentDataOffset = 0;
+ _currentDataLength = _le.readUShort();
+ if (_currentDataLength > MAX_RECORD_DATA_SIZE) {
+ throw new RecordFormatException("The content of an excel record cannot exceed "
+ + MAX_RECORD_DATA_SIZE + " bytes");
+ }
+ }
private void checkRecordPosition(int requiredByteCount) {
- if (remaining() < requiredByteCount) {
- if (isContinueNext() && autoContinue) {
- nextRecord();
- } else {
- throw new ArrayIndexOutOfBoundsException();
- }
+ int nAvailable = remaining();
+ if (nAvailable >= requiredByteCount) {
+ // all OK
+ return;
}
+ if (nAvailable == 0 && isContinueNext()) {
+ nextRecord();
+ return;
+ }
+ throw new RecordFormatException("Not enough data (" + nAvailable
+ + ") to read requested (" + requiredByteCount +") bytes");
}
/**
*/
public byte readByte() {
checkRecordPosition(LittleEndian.BYTE_SIZE);
-
- byte result = data[recordOffset];
- recordOffset += LittleEndian.BYTE_SIZE;
- pos += LittleEndian.BYTE_SIZE;
- return result;
+ _currentDataOffset += LittleEndian.BYTE_SIZE;
+ return _le.readByte();
}
/**
*/
public short readShort() {
checkRecordPosition(LittleEndian.SHORT_SIZE);
-
- short result = LittleEndian.getShort(data, recordOffset);
- recordOffset += LittleEndian.SHORT_SIZE;
- pos += LittleEndian.SHORT_SIZE;
- return result;
+ _currentDataOffset += LittleEndian.SHORT_SIZE;
+ return _le.readShort();
}
public int readInt() {
checkRecordPosition(LittleEndian.INT_SIZE);
-
- int result = LittleEndian.getInt(data, recordOffset);
- recordOffset += LittleEndian.INT_SIZE;
- pos += LittleEndian.INT_SIZE;
- return result;
+ _currentDataOffset += LittleEndian.INT_SIZE;
+ return _le.readInt();
}
public long readLong() {
checkRecordPosition(LittleEndian.LONG_SIZE);
-
- long result = LittleEndian.getLong(data, recordOffset);
- recordOffset += LittleEndian.LONG_SIZE;
- pos += LittleEndian.LONG_SIZE;
- return result;
+ _currentDataOffset += LittleEndian.LONG_SIZE;
+ return _le.readLong();
}
/**
*/
public int readUShort() {
checkRecordPosition(LittleEndian.SHORT_SIZE);
-
- int result = LittleEndian.getUShort(data, recordOffset);
- recordOffset += LittleEndian.SHORT_SIZE;
- pos += LittleEndian.SHORT_SIZE;
- return result;
+ _currentDataOffset += LittleEndian.SHORT_SIZE;
+ return _le.readUShort();
}
public double readDouble() {
checkRecordPosition(LittleEndian.DOUBLE_SIZE);
- long valueLongBits = LittleEndian.getLong(data, recordOffset);
+ _currentDataOffset += LittleEndian.DOUBLE_SIZE;
+ long valueLongBits = _le.readLong();
double result = Double.longBitsToDouble(valueLongBits);
if (Double.isNaN(result)) {
throw new RuntimeException("Did not expect to read NaN"); // (Because Excel typically doesn't write NaN
}
- recordOffset += LittleEndian.DOUBLE_SIZE;
- pos += LittleEndian.DOUBLE_SIZE;
return result;
}
public void readFully(byte[] buf) {
public void readFully(byte[] buf, int off, int len) {
checkRecordPosition(len);
- System.arraycopy(data, recordOffset, buf, off, len);
- recordOffset+=len;
- pos+=len;
+ _le.readFully(buf, off, len);
+ _currentDataOffset+=len;
}
public String readString() {
return new UnicodeString(this);
}
- /** Returns the remaining bytes for the current record.
- *
- * @return The remaining bytes of the current record.
- */
- public byte[] readRemainder() {
- int size = remaining();
- byte[] result = new byte[size];
- System.arraycopy(data, recordOffset, result, 0, size);
- recordOffset += size;
- pos += size;
- return result;
- }
+ /** Returns the remaining bytes for the current record.
+ *
+ * @return The remaining bytes of the current record.
+ */
+ public byte[] readRemainder() {
+ int size = remaining();
+ if (size ==0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ byte[] result = new byte[size];
+ readFully(result);
+ return result;
+ }
/** Reads all byte data for the current record, including any
* that overlaps into any following continue records.
return out.toByteArray();
}
- /** The remaining number of bytes in the <i>current</i> record.
- *
- * @return The number of bytes remaining in the current record
- */
- public int remaining() {
- return (currentLength - recordOffset);
- }
+ /** The remaining number of bytes in the <i>current</i> record.
+ *
+ * @return The number of bytes remaining in the current record
+ */
+ public int remaining() {
+ if (_currentDataLength == DATA_LEN_NEEDS_TO_BE_READ) {
+ // already read sid of next record. so current one is finished
+ return 0;
+ }
+ return _currentDataLength - _currentDataOffset;
+ }
- /** Returns true iif a Continue record is next in the excel stream
- *
- * @return True when a ContinueRecord is next.
- */
- public boolean isContinueNext() {
- return (nextSid == ContinueRecord.sid);
- }
+ /**
+ *
+ * @return <code>true</code> when a {@link ContinueRecord} is next.
+ */
+ private boolean isContinueNext() {
+ if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ && _currentDataOffset != _currentDataLength) {
+ throw new IllegalStateException("Should never be called before end of current record");
+ }
+ if (!hasNextRecord()) {
+ return false;
+ }
+ // At what point are records continued?
+ // - Often from within the char data of long strings (caller is within readStringCommon()).
+ // - From UnicodeString construction (many different points - call via checkRecordPosition)
+ // - During TextObjectRecord construction (just before the text, perhaps within the text,
+ // and before the formatting run data)
+ return _nextSid == ContinueRecord.sid;
+ }
}
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
/**
- * Title: Style Record<P>
+ * Title: Style Record (0x0293)<p/>
* Description: Describes a builtin to the gui or user defined style<P>
* REFERENCE: PG 390 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author aviks : string fixes for UserDefined Style
- * @version 2.0-pre
*/
public final class StyleRecord extends Record {
- public final static short sid = 0x0293;
-
- private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
-
- public final static short STYLE_USER_DEFINED = 0;
- public final static short STYLE_BUILT_IN = 1;
-
- // shared by both user defined and builtin styles
- private short field_1_xf_index; // TODO: bitfield candidate
-
- // only for built in styles
- private byte field_2_builtin_style;
- private byte field_3_outline_style_level;
-
- // only for user defined styles
- private short field_2_name_length; //OO doc says 16 bit length, so we believe
- private byte field_3_string_options;
- private String field_4_name;
-
- public StyleRecord()
- {
- }
-
- public StyleRecord(RecordInputStream in)
- {
- field_1_xf_index = in.readShort();
- if (getType() == STYLE_BUILT_IN)
- {
- field_2_builtin_style = in.readByte();
- field_3_outline_style_level = in.readByte();
- }
- else if (getType() == STYLE_USER_DEFINED)
- {
- field_2_name_length = in.readShort();
-
- // Some files from Crystal Reports lack
- // the remaining fields, which is naughty
- if(in.remaining() > 0) {
- field_3_string_options = in.readByte();
-
- byte[] string = in.readRemainder();
- if (fHighByte.isSet(field_3_string_options)) {
- field_4_name= StringUtil.getFromUnicodeBE(string, 0, field_2_name_length);
- } else {
- field_4_name=StringUtil.getFromCompressedUnicode(string, 0, field_2_name_length);
- }
- }
- }
-
- // todo sanity check exception to make sure we're one or the other
- }
-
- /**
- * set the entire index field (including the type) (see bit setters that reference this method)
- * @param index bitmask
- */
-
- public void setIndex(short index)
- {
- field_1_xf_index = index;
- }
-
- // bitfields for field 1
-
- /**
- * set the type of the style (builtin or user-defined)
- * @see #STYLE_USER_DEFINED
- * @see #STYLE_BUILT_IN
- * @param type of style (userdefined/builtin)
- * @see #setIndex(short)
- */
-
- public void setType(short type)
- {
- field_1_xf_index = setField(field_1_xf_index, type, 0x8000, 15);
- }
-
- /**
- * set the actual index of the style extended format record
- * @see #setIndex(short)
- * @param index of the xf record
- */
-
- public void setXFIndex(short index)
- {
- field_1_xf_index = setField(field_1_xf_index, index, 0x1FFF, 0);
- }
-
- // end bitfields
- // only for user defined records
-
- /**
- * if this is a user defined record set the length of the style name
- * @param length of the style's name
- * @see #setName(String)
- */
-
- public void setNameLength(byte length)
- {
- field_2_name_length = length;
- }
-
- /**
- * set the style's name
- * @param name of the style
- * @see #setNameLength(byte)
- */
-
- public void setName(String name)
- {
- field_4_name = name;
-
- // Fix up the length
- field_2_name_length = (short)name.length();
- //TODO set name string options
- }
-
- // end user defined
- // only for buildin records
-
- /**
- * if this is a builtin style set teh number of the built in style
- * @param builtin style number (0-7)
- *
- */
-
- public void setBuiltin(byte builtin)
- {
- field_2_builtin_style = builtin;
- }
-
- /**
- * set the row or column level of the style (if builtin 1||2)
- */
-
- public void setOutlineStyleLevel(byte level)
- {
- field_3_outline_style_level = level;
- }
-
- // end builtin records
- // field 1
-
- /**
- * get the entire index field (including the type) (see bit getters that reference this method)
- * @return bitmask
- */
-
- public short getIndex()
- {
- return field_1_xf_index;
- }
-
- // bitfields for field 1
-
- /**
- * get the type of the style (builtin or user-defined)
- * @see #STYLE_USER_DEFINED
- * @see #STYLE_BUILT_IN
- * @return type of style (userdefined/builtin)
- * @see #getIndex()
- */
-
- public short getType()
- {
- return ( short ) ((field_1_xf_index & 0x8000) >> 15);
- }
-
- /**
- * get the actual index of the style extended format record
- * @see #getIndex()
- * @return index of the xf record
- */
-
- public short getXFIndex()
- {
- return ( short ) (field_1_xf_index & 0x1FFF);
- }
-
- // end bitfields
- // only for user defined records
-
- /**
- * if this is a user defined record get the length of the style name
- * @return length of the style's name
- * @see #getName()
- */
-
- public short getNameLength()
- {
- return field_2_name_length;
- }
-
- /**
- * get the style's name
- * @return name of the style
- * @see #getNameLength()
- */
-
- public String getName()
- {
- return field_4_name;
- }
-
- // end user defined
- // only for buildin records
-
- /**
- * if this is a builtin style get the number of the built in style
- * @return builtin style number (0-7)
- *
- */
-
- public byte getBuiltin()
- {
- return field_2_builtin_style;
- }
-
- /**
- * get the row or column level of the style (if builtin 1||2)
- */
-
- public byte getOutlineStyleLevel()
- {
- return field_3_outline_style_level;
- }
-
- // end builtin records
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("[STYLE]\n");
- buffer.append(" .xf_index_raw = ")
- .append(Integer.toHexString(getIndex())).append("\n");
- buffer.append(" .type = ")
- .append(Integer.toHexString(getType())).append("\n");
- buffer.append(" .xf_index = ")
- .append(Integer.toHexString(getXFIndex())).append("\n");
- if (getType() == STYLE_BUILT_IN)
- {
- buffer.append(" .builtin_style = ")
- .append(Integer.toHexString(getBuiltin())).append("\n");
- buffer.append(" .outline_level = ")
- .append(Integer.toHexString(getOutlineStyleLevel()))
- .append("\n");
- }
- else if (getType() == STYLE_USER_DEFINED)
- {
- buffer.append(" .name_length = ")
- .append(Integer.toHexString(getNameLength())).append("\n");
- buffer.append(" .name = ").append(getName())
- .append("\n");
- }
- buffer.append("[/STYLE]\n");
- return buffer.toString();
- }
-
- private short setField(int fieldValue, int new_value, int mask,
- int shiftLeft)
- {
- return ( short ) ((fieldValue & ~mask)
- | ((new_value << shiftLeft) & mask));
- }
-
- public int serialize(int offset, byte [] data)
- {
- LittleEndian.putShort(data, 0 + offset, sid);
- if (getType() == STYLE_BUILT_IN)
- {
- LittleEndian.putShort(data, 2 + offset,
- (( short ) 0x04)); // 4 bytes (8 total)
- }
- else
- {
- LittleEndian.putShort(data, 2 + offset,
- (( short ) (getRecordSize()-4)));
- }
- LittleEndian.putShort(data, 4 + offset, getIndex());
- if (getType() == STYLE_BUILT_IN)
- {
- data[ 6 + offset ] = getBuiltin();
- data[ 7 + offset ] = getOutlineStyleLevel();
- }
- else
- {
- LittleEndian.putShort(data, 6 + offset , getNameLength());
- data[8+offset]=this.field_3_string_options;
- StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
- }
- return getRecordSize();
- }
-
- public int getRecordSize()
- {
- int retval;
-
- if (getType() == STYLE_BUILT_IN)
- {
- retval = 8;
- }
- else
- {
- if (fHighByte.isSet(field_3_string_options)) {
- retval= 9+2*getNameLength();
- }else {
- retval = 9 + getNameLength();
- }
- }
- return retval;
- }
-
- public short getSid()
- {
- return sid;
- }
+ public final static short sid = 0x0293;
+
+ private static final BitField is16BitUnicodeFlag = BitFieldFactory.getInstance(0x01);
+
+ private static final BitField styleIndexMask = BitFieldFactory.getInstance(0x0FFF);
+ private static final BitField isBuiltinFlag = BitFieldFactory.getInstance(0x8000);
+
+ /** shared by both user defined and built-in styles */
+ private int field_1_xf_index;
+
+ // only for built in styles
+ private int field_2_builtin_style;
+ private int field_3_outline_style_level;
+
+ // only for user defined styles
+ private int field_3_string_options;
+ private String field_4_name;
+
+ /**
+ * creates a new style record, initially set to 'built-in'
+ */
+ public StyleRecord() {
+ field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
+ }
+
+ public StyleRecord(RecordInputStream in) {
+ field_1_xf_index = in.readShort();
+ if (isBuiltin()) {
+ field_2_builtin_style = in.readByte();
+ field_3_outline_style_level = in.readByte();
+ } else {
+ int field_2_name_length = in.readShort();
+
+ if(in.remaining() < 1) {
+ // Some files from Crystal Reports lack the is16BitUnicode byte
+ // the remaining fields, which is naughty
+ if (field_2_name_length != 0) {
+ throw new RecordFormatException("Ran out of data reading style record");
+ }
+ // guess this is OK if the string length is zero
+ field_4_name = "";
+ } else {
+
+ int is16BitUnicode = in.readByte();
+ if (is16BitUnicodeFlag.isSet(is16BitUnicode)) {
+ field_4_name = StringUtil.readUnicodeLE(in, field_2_name_length);
+ } else {
+ field_4_name = StringUtil.readCompressedUnicode(in, field_2_name_length);
+ }
+ }
+ }
+ }
+
+ /**
+ * set the actual index of the style extended format record
+ * @param xfIndex of the xf record
+ */
+ public void setXFIndex(int xfIndex) {
+ field_1_xf_index = styleIndexMask.setValue(field_1_xf_index, xfIndex);
+ }
+
+ /**
+ * get the actual index of the style extended format record
+ * @see #getIndex()
+ * @return index of the xf record
+ */
+ public int getXFIndex() {
+ return styleIndexMask.getValue(field_1_xf_index);
+ }
+
+ /**
+ * set the style's name
+ * @param name of the style
+ */
+ public void setName(String name) {
+ field_4_name = name;
+ field_3_string_options = StringUtil.hasMultibyte(name) ? 0x01 : 0x00;
+ field_1_xf_index = isBuiltinFlag.clear(field_1_xf_index);
+ }
+
+ /**
+ * if this is a builtin style set the number of the built in style
+ * @param builtinStyleId style number (0-7)
+ *
+ */
+ public void setBuiltinStyle(int builtinStyleId) {
+ field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
+ field_2_builtin_style = builtinStyleId;
+ }
+
+ /**
+ * set the row or column level of the style (if builtin 1||2)
+ */
+ public void setOutlineStyleLevel(int level) {
+ field_3_outline_style_level = level & 0x00FF;
+ }
+
+ public boolean isBuiltin(){
+ return isBuiltinFlag.isSet(field_1_xf_index);
+ }
+
+ /**
+ * get the style's name
+ * @return name of the style
+ */
+ public String getName() {
+ return field_4_name;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("[STYLE]\n");
+ sb.append(" .xf_index_raw =").append(HexDump.shortToHex(field_1_xf_index)).append("\n");
+ sb.append(" .type =").append(isBuiltin() ? "built-in" : "user-defined").append("\n");
+ sb.append(" .xf_index =").append(HexDump.shortToHex(getXFIndex())).append("\n");
+ if (isBuiltin()){
+ sb.append(" .builtin_style=").append(HexDump.byteToHex(field_2_builtin_style)).append("\n");
+ sb.append(" .outline_level=").append(HexDump.byteToHex(field_3_outline_style_level)).append("\n");
+ } else {
+ sb.append(" .name =").append(getName()).append("\n");
+ }
+ sb.append("[/STYLE]\n");
+ return sb.toString();
+ }
+
+
+ private int getDataSize() {
+ if (isBuiltin()) {
+ return 4; // short, byte, byte
+ }
+ int size = 2 + 3; // short
+ if (is16BitUnicodeFlag.isSet(field_3_string_options)) {
+ size += 2 * field_4_name.length();
+ } else {
+ size += field_4_name.length();
+ }
+ return size;
+ }
+
+ public int serialize(int offset, byte [] data) {
+ int dataSize = getDataSize();
+ LittleEndian.putShort(data, 0 + offset, sid);
+ LittleEndian.putUShort(data, 2 + offset, dataSize);
+
+ LittleEndian.putUShort(data, 4 + offset, field_1_xf_index);
+ if (isBuiltin()) {
+ LittleEndian.putByte(data, 6 + offset, field_2_builtin_style);
+ LittleEndian.putByte(data, 7 + offset, field_3_outline_style_level);
+ } else {
+ LittleEndian.putUShort(data, 6 + offset, field_4_name.length());
+ LittleEndian.putByte(data, 8 + offset, field_3_string_options);
+ StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
+ }
+ return 4+dataSize;
+ }
+
+ public int getRecordSize() {
+ return 4 + getDataSize();
+ }
+
+ public short getSid()
+ {
+ return sid;
+ }
}
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.LittleEndianOutputStream;
out.writeShort(_unknownShort13);
}
private static Ptg readRefPtg(byte[] formulaRawBytes) {
- byte[] data = new byte[formulaRawBytes.length + 4];
- LittleEndian.putUShort(data, 0, -5555);
- LittleEndian.putUShort(data, 2, formulaRawBytes.length);
- System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
- RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
- in.nextRecord();
- byte ptgSid = in.readByte();
+ LittleEndianInput in = new LittleEndianByteArrayInputStream(formulaRawBytes);
+ byte ptgSid = in.readByte();
switch(ptgSid) {
case AreaPtg.sid: return new AreaPtg(in);
case Area3DPtg.sid: return new Area3DPtg(in);
- case RefPtg.sid: return new RefPtg(in);
+ case RefPtg.sid: return new RefPtg(in);
case Ref3DPtg.sid: return new Ref3DPtg(in);
}
return null;
* @param offset of the record's data (provided a big array of the file)
*/
public SupBookRecord(RecordInputStream in) {
+ int recLen = in.remaining();
+
field_1_number_of_sheets = in.readShort();
- if(in.getLength() > SMALL_RECORD_SIZE) {
+ if(recLen > SMALL_RECORD_SIZE) {
// 5.38.1 External References
_isAddInFunctions = false;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
/**
* The TXO record (0x01B6) is used to define the properties of a text box. It is
_text = new HSSFRichTextString(text);
if (field_7_formattingDataLength > 0) {
- if (in.isContinueNext() && in.remaining() == 0) {
- in.nextRecord();
- processFontRuns(in, _text, field_7_formattingDataLength);
- } else {
- throw new RecordFormatException(
- "Expected Continue Record to hold font runs for TextObjectRecord");
- }
+ processFontRuns(in, _text, field_7_formattingDataLength);
}
}
throw new RecordFormatException("Bad format run data length " + formattingRunDataLength
+ ")");
}
- if (in.remaining() != formattingRunDataLength) {
- throw new RecordFormatException("Expected " + formattingRunDataLength
- + " bytes but got " + in.remaining());
- }
int nRuns = formattingRunDataLength / FORMAT_RUN_ENCODED_SIZE;
for (int i = 0; i < nRuns; i++) {
short index = in.readShort();
private int serializeTXORecord(int offset, byte[] data) {
int dataSize = getDataSize();
+ int recSize = dataSize+4;
+ LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
- LittleEndian.putUShort(data, 0 + offset, TextObjectRecord.sid);
- LittleEndian.putUShort(data, 2 + offset, dataSize);
-
+ out.writeShort(TextObjectRecord.sid);
+ out.writeShort(dataSize);
- LittleEndian.putUShort(data, 4 + offset, field_1_options);
- LittleEndian.putUShort(data, 6 + offset, field_2_textOrientation);
- LittleEndian.putUShort(data, 8 + offset, field_3_reserved4);
- LittleEndian.putUShort(data, 10 + offset, field_4_reserved5);
- LittleEndian.putUShort(data, 12 + offset, field_5_reserved6);
- LittleEndian.putUShort(data, 14 + offset, _text.length());
- LittleEndian.putUShort(data, 16 + offset, getFormattingDataLength());
- LittleEndian.putInt(data, 18 + offset, field_8_reserved7);
+ out.writeShort(field_1_options);
+ out.writeShort(field_2_textOrientation);
+ out.writeShort(field_3_reserved4);
+ out.writeShort(field_4_reserved5);
+ out.writeShort(field_5_reserved6);
+ out.writeShort(_text.length());
+ out.writeShort(getFormattingDataLength());
+ out.writeInt(field_8_reserved7);
if (_linkRefPtg != null) {
- int pos = offset+22;
int formulaSize = _linkRefPtg.getSize();
- LittleEndian.putUShort(data, pos, formulaSize);
- pos += LittleEndian.SHORT_SIZE;
- LittleEndian.putInt(data, pos, _unknownPreFormulaInt);
- pos += LittleEndian.INT_SIZE;
- _linkRefPtg.writeBytes(data, pos);
- pos += formulaSize;
+ out.writeShort(formulaSize);
+ out.writeInt(_unknownPreFormulaInt);
+ _linkRefPtg.write(out);
if (_unknownPostFormulaByte != null) {
- LittleEndian.putByte(data, pos, _unknownPostFormulaByte.byteValue());
- pos += LittleEndian.BYTE_SIZE;
+ out.writeByte(_unknownPostFormulaByte.byteValue());
}
}
-
- return 4 + dataSize;
+ return recSize;
}
private int serializeTrailingRecords(int offset, byte[] data) {
* @author Andrew C. Oliver
* @author Marc Johnson (mjohnson at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
- * @version 2.0-pre
*/
-
-public class UnicodeString
- implements Comparable
-{
- public final static short sid = 0xFFF;
+public final class UnicodeString implements Comparable {
private short field_1_charCount; // = 0;
private byte field_2_optionflags; // = 0;
private String field_3_string; // = null;
private static final BitField richText = BitFieldFactory.getInstance(0x8);
public static class FormatRun implements Comparable {
- private short character;
- private short fontIndex;
+ short character;
+ short fontIndex;
public FormatRun(short character, short fontIndex) {
this.character = character;
setString(str);
}
- /**
- * construct a unicode string record and fill its fields, ID is ignored
- * @param in the RecordInputstream to read the record from
- */
-
- public UnicodeString(RecordInputStream in)
- {
- fillFields(in); // TODO - inline
- }
public int hashCode()
&& field_3_string.equals(other.field_3_string));
if (!eq) return false;
- //Ok string appears to be equal but now lets compare formatting runs
+ //OK string appears to be equal but now lets compare formatting runs
if ((field_4_format_runs == null) && (other.field_4_format_runs == null))
- //Strings are equal, and there are not formtting runs.
+ //Strings are equal, and there are not formatting runs.
return true;
if (((field_4_format_runs == null) && (other.field_4_format_runs != null)) ||
(field_4_format_runs != null) && (other.field_4_format_runs == null))
}
/**
+ * construct a unicode string record and fill its fields, ID is ignored
* @param in the RecordInputstream to read the record from
*/
- protected void fillFields(RecordInputStream in)
- {
+ public UnicodeString(RecordInputStream in) {
field_1_charCount = in.readShort();
field_2_optionflags = in.readByte();
extensionLength = in.readInt();
}
- //Now need to get the string data.
- //Turn off autocontinuation so that we can catch the continue boundary
- in.setAutoContinue(false);
- StringBuffer tmpString = new StringBuffer(field_1_charCount);
- int stringCharCount = field_1_charCount;
boolean isCompressed = ((field_2_optionflags & 1) == 0);
- while (stringCharCount != 0) {
- if (in.remaining() == 0) {
- if (in.isContinueNext()) {
- in.nextRecord();
- //Check if we are now reading, compressed or uncompressed unicode.
- byte optionflags = in.readByte();
- isCompressed = ((optionflags & 1) == 0);
- } else
- throw new RecordFormatException("Expected continue record.");
- }
- if (isCompressed) {
- char ch = (char)in.readUByte(); // avoid sex
- tmpString.append(ch);
- } else {
- char ch = (char) in.readShort();
- tmpString.append(ch);
- }
- stringCharCount --;
+ if (isCompressed) {
+ field_3_string = in.readCompressedUnicode(field_1_charCount);
+ } else {
+ field_3_string = in.readUnicodeLEString(field_1_charCount);
}
- field_3_string = tmpString.toString();
- //Turn back on autocontinuation
- in.setAutoContinue(true);
-
+
if (isRichText() && (runCount > 0)) {
field_4_format_runs = new ArrayList(runCount);
}
/**
- * get the actual string this contains as a java String object
- *
- *
- * @return String
- *
+ * @return the actual string this contains as a java String object
*/
-
public String getString()
{
return field_3_string;
}
}
if (useUTF16)
- //Set the uncomressed bit
+ //Set the uncompressed bit
field_2_optionflags = highByte.setByte(field_2_optionflags);
else field_2_optionflags = highByte.clearByte(field_2_optionflags);
}
//Make sure that we now say that we are a rich string
field_2_optionflags = richText.setByte(field_2_optionflags);
- }
+ }
public Iterator formatIterator() {
if (field_4_format_runs != null)
LittleEndian.putShort(data, offset, ContinueRecord.sid);
offset+=2;
- //Record the location of the last continue legnth position, but dont write
- //anything there yet (since we dont know what it will be!)
+ //Record the location of the last continue length position, but don't write
+ //anything there yet (since we don't know what it will be!)
stats.lastLengthPos = offset;
offset += 2;
stats.remainingSize = SSTRecord.MAX_RECORD_SIZE-4;
}
return offset;
- }
+ }
public int serialize(UnicodeRecordStats stats, final int offset, byte [] data)
{
//Basic string overhead
pos = writeContinueIfRequired(stats, 3, pos, data);
- // byte[] retval = new byte[ 3 + (getString().length() * charsize)];
LittleEndian.putShort(data, pos, getCharCount());
pos += 2;
data[ pos ] = getOptionFlags();
//Check to see if the offset occurs mid string, if so then we need to add
//the byte to start with that represents the first byte of the continue record.
if (strSize > stats.remainingSize) {
- //Ok the offset occurs half way through the string, that means that
+ //OK the offset occurs half way through the string, that means that
//we need an extra byte after the continue record ie we didnt finish
//writing out the string the 1st time through
//But hang on, how many continue records did we span? What if this is
//a REALLY long string. We need to work this all out.
- int ammountThatCantFit = strSize;
+ int amountThatCantFit = strSize;
int strPos = 0;
- while (ammountThatCantFit > 0) {
- int ammountWritten = Math.min(stats.remainingSize, ammountThatCantFit);
- //Make sure that the ammount that cant fit takes into account
+ while (amountThatCantFit > 0) {
+ int amountWritten = Math.min(stats.remainingSize, amountThatCantFit);
+ //Make sure that the amount that can't fit takes into account
//whether we are writing double byte unicode
if (isUncompressedUnicode()) {
//We have the '-1' here because whether this is the first record or
//subsequent continue records, there is always the case that the
- //number of bytes in a string on doube byte boundaries is actually odd.
- if ( ( (ammountWritten ) % 2) == 1)
- ammountWritten--;
+ //number of bytes in a string on double byte boundaries is actually odd.
+ if ( ( (amountWritten ) % 2) == 1)
+ amountWritten--;
}
- System.arraycopy(strBytes, strPos, data, pos, ammountWritten);
- pos += ammountWritten;
- strPos += ammountWritten;
- stats.recordSize += ammountWritten;
- stats.remainingSize -= ammountWritten;
+ System.arraycopy(strBytes, strPos, data, pos, amountWritten);
+ pos += amountWritten;
+ strPos += amountWritten;
+ stats.recordSize += amountWritten;
+ stats.remainingSize -= amountWritten;
//Ok lets subtract what we can write
- ammountThatCantFit -= ammountWritten;
+ amountThatCantFit -= amountWritten;
//Each iteration of this while loop is another continue record, unless
//everything now fits.
- if (ammountThatCantFit > 0) {
+ if (amountThatCantFit > 0) {
//We know that a continue WILL be requied, but use this common method
- pos = writeContinueIfRequired(stats, ammountThatCantFit, pos, data);
+ pos = writeContinueIfRequired(stats, amountThatCantFit, pos, data);
//The first byte after a continue mid string is the extra byte to
//indicate if this run is compressed or not.
return highByte.isSet(getOptionFlags());
}
- /** Returns the size of this record, given the ammount of record space
+ /** Returns the size of this record, given the amount of record space
* remaining, it will also include the size of writing a continue record.
*/
}
}
-
-
- public short getSid()
- {
- return sid;
- }
-
public int compareTo(Object obj)
{
UnicodeString str = ( UnicodeString ) obj;
}
//Well the format runs are equal as well!, better check the ExtRst data
- //Which by the way we dont know how to decode!
+ //Which by the way we don't know how to decode!
if ((field_5_ext_rst == null) && (str.field_5_ext_rst == null))
return 0;
if ((field_5_ext_rst == null) && (str.field_5_ext_rst != null))
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
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 org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
/**
- * Title: Write Access Record<P>
- * Description: Stores the username of that who owns the spreadsheet generator
- * (on unix the user's login, on Windoze its the name you typed when
- * you installed the thing)<P>
- * REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
+ * Title: Write Access Record (0x005C)<p/>
+ *
+ * Description: Stores the username of that who owns the spreadsheet generator (on unix the user's
+ * login, on Windoze its the name you typed when you installed the thing)
+ * <p/>
+ * REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
+ * <p/>
+ *
* @author Andrew C. Oliver (acoliver at apache dot org)
- * @version 2.0-pre
*/
-
-public class WriteAccessRecord
- extends Record
-{
- public final static short sid = 0x5c;
- private String field_1_username;
-
- public WriteAccessRecord()
- {
- }
-
- public WriteAccessRecord(RecordInputStream in)
- {
- byte[] data = in.readRemainder();
- //The string is always 112 characters (padded with spaces), therefore
- //this record can not be continued.
-
- //What a wierd record, it is not really a unicode string because the
- //header doesnt provide a correct size indication.???
- //But the header is present, so we need to skip over it.
- //Odd, Odd, Odd ;-)
- field_1_username = StringUtil.getFromCompressedUnicode(data, 3, data.length - 3);
- }
-
- /**
- * set the username for the user that created the report. HSSF uses the logged in user.
- * @param username of the user who is logged in (probably "tomcat" or "apache")
- */
-
- public void setUsername(String username)
- {
- field_1_username = username;
- }
-
- /**
- * get the username for the user that created the report. HSSF uses the logged in user. On
- * natively created M$ Excel sheet this would be the name you typed in when you installed it
- * in most cases.
- * @return username of the user who is logged in (probably "tomcat" or "apache")
- */
-
- public String getUsername()
- {
- return field_1_username;
- }
-
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("[WRITEACCESS]\n");
- buffer.append(" .name = ")
- .append(field_1_username.toString()).append("\n");
- buffer.append("[/WRITEACCESS]\n");
- return buffer.toString();
- }
-
- public int serialize(int offset, byte [] data)
- {
- String username = getUsername();
- StringBuffer temp = new StringBuffer(0x70 - (0x3));
-
- temp.append(username);
- while (temp.length() < 0x70 - 0x3)
- {
- temp.append(
- " "); // (70 = fixed lenght -3 = the overhead bits of unicode string)
- }
- username = temp.toString();
- UnicodeString str = new UnicodeString(username);
- str.setOptionFlags(( byte ) 0x0);
-
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putShort(data, 2 + offset, (short)112); // 112 bytes (115 total)
- UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats();
- stats.recordSize += 4;
- stats.remainingSize-= 4;
- str.serialize(stats, 4 + offset, data);
-
- return getRecordSize();
- }
-
- public int getRecordSize()
- {
- return 116;
- }
-
- public short getSid()
- {
- return sid;
- }
+public final class WriteAccessRecord extends Record {
+ private static final byte PAD_CHAR = (byte) ' ';
+ public final static short sid = 0x005C;
+ private static final int DATA_SIZE = 112;
+ private String field_1_username;
+ /** this record is always padded to a constant length */
+ private byte[] padding;
+
+ public WriteAccessRecord() {
+ setUsername("");
+ padding = new byte[DATA_SIZE - 3];
+ }
+
+ public WriteAccessRecord(RecordInputStream in) {
+ if (in.remaining() > DATA_SIZE) {
+ throw new RecordFormatException("Expected data size (" + DATA_SIZE + ") but got ("
+ + in.remaining() + ")");
+ }
+ // The string is always 112 characters (padded with spaces), therefore
+ // this record can not be continued.
+
+ int nChars = in.readUShort();
+ int is16BitFlag = in.readUByte();
+ int expectedPadSize = DATA_SIZE - 3;
+ if ((is16BitFlag & 0x01) == 0x00) {
+ field_1_username = StringUtil.readCompressedUnicode(in, nChars);
+ expectedPadSize -= nChars;
+ } else {
+ field_1_username = StringUtil.readUnicodeLE(in, nChars);
+ expectedPadSize -= nChars * 2;
+ }
+ padding = new byte[expectedPadSize];
+ int padSize = in.remaining();
+ in.readFully(padding, 0, padSize);
+ if (padSize < expectedPadSize) {
+ // this occurs in a couple of test examples: "42564.xls",
+ // "bug_42794.xls"
+ Arrays.fill(padding, padSize, expectedPadSize, PAD_CHAR);
+ }
+ }
+
+ /**
+ * set the username for the user that created the report. HSSF uses the
+ * logged in user.
+ *
+ * @param username of the user who is logged in (probably "tomcat" or "apache")
+ */
+ public void setUsername(String username) {
+ boolean is16bit = StringUtil.hasMultibyte(username);
+ int encodedByteCount = 3 + username.length() * (is16bit ? 2 : 1);
+ int paddingSize = DATA_SIZE - encodedByteCount;
+ if (paddingSize < 0) {
+ throw new IllegalArgumentException("Name is too long: " + username);
+ }
+ padding = new byte[paddingSize];
+ Arrays.fill(padding, PAD_CHAR);
+
+ field_1_username = username;
+ }
+
+ /**
+ * get the username for the user that created the report. HSSF uses the
+ * logged in user. On natively created M$ Excel sheet this would be the name
+ * you typed in when you installed it in most cases.
+ *
+ * @return username of the user who is logged in (probably "tomcat" or "apache")
+ */
+ public String getUsername() {
+ return field_1_username;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[WRITEACCESS]\n");
+ buffer.append(" .name = ").append(field_1_username.toString()).append("\n");
+ buffer.append("[/WRITEACCESS]\n");
+ return buffer.toString();
+ }
+
+ public int serialize(int offset, byte[] data) {
+ String username = getUsername();
+ boolean is16bit = StringUtil.hasMultibyte(username);
+
+ LittleEndian.putUShort(data, 0 + offset, sid);
+ LittleEndian.putUShort(data, 2 + offset, DATA_SIZE);
+ LittleEndian.putUShort(data, 4 + offset, username.length());
+ LittleEndian.putByte(data, 6 + offset, is16bit ? 0x01 : 0x00);
+ int pos = offset + 7;
+ if (is16bit) {
+ StringUtil.putUnicodeLE(username, data, pos);
+ pos += username.length() * 2;
+ } else {
+ StringUtil.putCompressedUnicode(username, data, pos);
+ pos += username.length();
+ }
+ System.arraycopy(padding, 0, data, pos, padding.length);
+ return 4 + DATA_SIZE;
+ }
+
+ public int getRecordSize() {
+ return 4 + DATA_SIZE;
+ }
+
+ public short getSid() {
+ return sid;
+ }
}
package org.apache.poi.hssf.record.constant;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+import org.apache.poi.util.StringUtil;
/**
* To support Constant Values (2.5.7) as required by the CRN record.
// no instances of this class
}
- public static Object[] parse(RecordInputStream in, int nValues) {
+ public static Object[] parse(LittleEndianInput in, int nValues) {
Object[] result = new Object[nValues];
for (int i = 0; i < result.length; i++) {
result[i] = readAConstantValue(in);
return result;
}
- private static Object readAConstantValue(RecordInputStream in) {
+ private static Object readAConstantValue(LittleEndianInput in) {
byte grbit = in.readByte();
switch(grbit) {
case TYPE_EMPTY:
case TYPE_NUMBER:
return new Double(in.readDouble());
case TYPE_STRING:
- return in.readUnicodeString();
+ return new UnicodeString(StringUtil.readUnicodeString(in));
case TYPE_BOOLEAN:
return readBoolean(in);
case TYPE_ERROR_CODE:
throw new RuntimeException("Unknown grbit value (" + grbit + ")");
}
- private static Object readBoolean(RecordInputStream in) {
+ private static Object readBoolean(LittleEndianInput in) {
byte val = (byte)in.readLong(); // 7 bytes 'not used'
switch(val) {
case FALSE_ENCODING:
return urs.recordSize;
}
- public static void encode(byte[] data, int offset, Object[] values) {
- int currentOffset = offset;
+ public static void encode(LittleEndianOutput out, Object[] values) {
for (int i = 0; i < values.length; i++) {
- currentOffset += encodeSingleValue(data, currentOffset, values[i]);
+ encodeSingleValue(out, values[i]);
}
}
- private static int encodeSingleValue(byte[] data, int offset, Object value) {
+ private static void encodeSingleValue(LittleEndianOutput out, Object value) {
if (value == EMPTY_REPRESENTATION) {
- LittleEndian.putByte(data, offset, TYPE_EMPTY);
- LittleEndian.putLong(data, offset+1, 0L);
- return 9;
+ out.writeByte(TYPE_EMPTY);
+ out.writeLong(0L);
+ return;
}
if (value instanceof Boolean) {
Boolean bVal = ((Boolean)value);
- LittleEndian.putByte(data, offset, TYPE_BOOLEAN);
+ out.writeByte(TYPE_BOOLEAN);
long longVal = bVal.booleanValue() ? 1L : 0L;
- LittleEndian.putLong(data, offset+1, longVal);
- return 9;
+ out.writeLong(longVal);
+ return;
}
if (value instanceof Double) {
Double dVal = (Double) value;
- LittleEndian.putByte(data, offset, TYPE_NUMBER);
- LittleEndian.putDouble(data, offset+1, dVal.doubleValue());
- return 9;
+ out.writeByte(TYPE_NUMBER);
+ out.writeDouble(dVal.doubleValue());
+ return;
}
if (value instanceof UnicodeString) {
UnicodeString usVal = (UnicodeString) value;
- LittleEndian.putByte(data, offset, TYPE_STRING);
- UnicodeRecordStats urs = new UnicodeRecordStats();
- usVal.serialize(urs, offset +1, data);
- return 1 + urs.recordSize;
+ out.writeByte(TYPE_STRING);
+ StringUtil.writeUnicodeString(out, usVal.getString());
+ return;
}
if (value instanceof ErrorConstant) {
ErrorConstant ecVal = (ErrorConstant) value;
- LittleEndian.putByte(data, offset, TYPE_ERROR_CODE);
- LittleEndian.putUShort(data, offset+1, ecVal.getErrorCode());
- LittleEndian.putUShort(data, offset+3, 0);
- LittleEndian.putInt(data, offset+5, 0);
- return 9;
+ out.writeByte(TYPE_ERROR_CODE);
+ long longVal = ecVal.getErrorCode();
+ out.writeLong(longVal);
+ return;
}
throw new IllegalStateException("Unexpected value type (" + value.getClass().getName() + "'");
buf.append(")");
}
- public abstract void writeBytes(byte[] array, int offset);
public abstract int getSize();
\r
package org.apache.poi.hssf.record.formula;\r
\r
-import org.apache.poi.hssf.record.RecordInputStream;\r
-import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.LittleEndianInput;\r
+import org.apache.poi.util.LittleEndianOutput;\r
\r
/**\r
- * Common superclass of 2-D area refs \r
+ * Common superclass of 2-D area refs\r
*/\r
public abstract class Area2DPtgBase extends AreaPtgBase {\r
- private final static int SIZE = 9;\r
+ private final static int SIZE = 9;\r
\r
protected Area2DPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {\r
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);\r
}\r
- protected Area2DPtgBase(RecordInputStream in) {\r
+\r
+ protected Area2DPtgBase(LittleEndianInput in) {\r
readCoordinates(in);\r
}\r
+\r
protected abstract byte getSid();\r
\r
- public final void writeBytes(byte [] array, int offset) {\r
- LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());\r
- writeCoordinates(array, offset+1); \r
+ public final void write(LittleEndianOutput out) {\r
+ out.writeByte(getSid() + getPtgClass());\r
+ writeCoordinates(out);\r
}\r
+\r
public Area2DPtgBase(String arearef) {\r
- super(arearef);\r
+ super(arearef);\r
}\r
+\r
public final int getSize() {\r
return SIZE;\r
}\r
+\r
public final String toFormulaString() {\r
- return formatReferenceAsString();\r
+ return formatReferenceAsString();\r
+ }\r
+\r
+ public final String toString() {\r
+ StringBuffer sb = new StringBuffer();\r
+ sb.append(getClass().getName());\r
+ sb.append(" [");\r
+ sb.append(formatReferenceAsString());\r
+ sb.append("]");\r
+ return sb.toString();\r
}\r
- public final String toString() {\r
- StringBuffer sb = new StringBuffer();\r
- sb.append(getClass().getName());\r
- sb.append(" [");\r
- sb.append(formatReferenceAsString());\r
- sb.append("]");\r
- return sb.toString();\r
- }\r
}\r
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.formula.ExternSheetReferenceToken;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.WorkbookDependentFormula;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Title: Area 3D Ptg - 3D reference (Sheet + Area)<P>
setExternSheetIndex( externIdx );
}
- public Area3DPtg(RecordInputStream in) {
+ public Area3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readShort();
readCoordinates(in);
}
return sb.toString();
}
- public void writeBytes(byte[] array, int offset) {
- LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
- LittleEndian.putUShort(array, 1 + offset, field_1_index_extern_sheet);
- writeCoordinates(array, offset+3);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_index_extern_sheet);
+ writeCoordinates(out);
}
public int getSize() {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* AreaErr - handles deleted cell area references.
unused2 = 0;
}
- public AreaErrPtg(RecordInputStream in) {
+ public AreaErrPtg(LittleEndianInput in) {
// 8 bytes unused:
unused1 = in.readInt();
unused2 = in.readInt();
}
- public void writeBytes(byte[] array, int offset) {
- LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
- LittleEndian.putInt(array, offset + 1, unused1);
- LittleEndian.putInt(array, offset + 5, unused2);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeInt(unused1);
+ out.writeInt(unused2);
}
public String toFormulaString() {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
public final class AreaNPtg extends Area2DPtgBase {
public final static short sid = 0x2D;
- public AreaNPtg(RecordInputStream in) {
+ public AreaNPtg(LittleEndianInput in) {
super(in);
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
}
- public AreaPtg(RecordInputStream in) {
+ public AreaPtg(LittleEndianInput in) {
super(in);
}
public AreaPtg(String arearef) {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
private int field_3_first_column;
/** zero based, unsigned 8 bit */
private int field_4_last_column;
-
+
private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
protected AreaPtgBase() {
// do nothing
}
-
+
protected AreaPtgBase(String arearef) {
AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell();
setFirstColRelative(!firstCell.isColAbsolute());
setLastColRelative(!lastCell.isColAbsolute());
setFirstRowRelative(!firstCell.isRowAbsolute());
- setLastRowRelative(!lastCell.isRowAbsolute());
+ setLastRowRelative(!lastCell.isRowAbsolute());
}
-
+
protected AreaPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
-
+
checkColumnBounds(firstColumn);
checkColumnBounds(lastColumn);
checkRowBounds(firstRow);
checkRowBounds(lastRow);
-
+
if (lastRow > firstRow) {
setFirstRow(firstRow);
setLastRow(lastRow);
setFirstRowRelative(lastRowRelative);
setLastRowRelative(firstRowRelative);
}
-
+
if (lastColumn > firstColumn) {
setFirstColumn(firstColumn);
setLastColumn(lastColumn);
setFirstColRelative(lastColRelative);
setLastColRelative(firstColRelative);
}
- }
+ }
private static void checkColumnBounds(int colIx) {
if((colIx & 0x0FF) != colIx) {
}
}
- protected final void readCoordinates(RecordInputStream in) {
+ protected final void readCoordinates(LittleEndianInput in) {
field_1_first_row = in.readUShort();
field_2_last_row = in.readUShort();
field_3_first_column = in.readUShort();
field_4_last_column = in.readUShort();
}
- protected final void writeCoordinates(byte[] array, int offset) {
- LittleEndian.putUShort(array, offset + 0, field_1_first_row);
- LittleEndian.putUShort(array, offset + 2, field_2_last_row);
- LittleEndian.putUShort(array, offset + 4, field_3_first_column);
- LittleEndian.putUShort(array, offset + 6, field_4_last_column);
+ protected final void writeCoordinates(LittleEndianOutput out) {
+ out.writeShort(field_1_first_row);
+ out.writeShort(field_2_last_row);
+ out.writeShort(field_3_first_column);
+ out.writeShort(field_4_last_column);
}
/**
}
/**
- * @param rowIx last row number in the area
+ * @param rowIx last row number in the area
*/
public final void setLastRow(int rowIx) {
checkRowBounds(rowIx);
public final boolean isFirstRowRelative() {
return rowRelative.isSet(field_3_first_column);
}
-
+
/**
* sets the first row to relative or not
* @param rel is relative or not.
public final boolean isFirstColRelative() {
return colRelative.isSet(field_3_first_column);
}
-
+
/**
- * set whether the first column is relative
+ * set whether the first column is relative
*/
public final void setFirstColRelative(boolean rel) {
field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
public final boolean isLastRowRelative() {
return rowRelative.isSet(field_4_last_column);
}
-
+
/**
* set whether the last row is relative or not
* @param rel <code>true</code> if the last row relative, else
public final boolean isLastColRelative() {
return colRelative.isSet(field_4_last_column);
}
-
+
/**
* set whether the last column should be relative or not
*/
public final void setLastColRelative(boolean rel) {
field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
}
-
+
/**
* set the last column in the area
*/
protected final String formatReferenceAsString() {
CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
-
+
if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
return (new AreaReference(topLeft, botRight)).formatAsString();
}
- return topLeft.formatAsString() + ":" + botRight.formatAsString();
+ return topLeft.formatAsString() + ":" + botRight.formatAsString();
}
-
+
public String toFormulaString() {
return formatReferenceAsString();
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.record.constant.ConstantValueParser;
import org.apache.poi.hssf.record.constant.ErrorConstant;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* ArrayPtg - handles arrays
private short token_2_rows;
private Object[] token_3_arrayValues;
- public ArrayPtg(RecordInputStream in) {
+ public ArrayPtg(LittleEndianInput in) {
field_1_reserved = new byte[RESERVED_FIELD_LEN];
// TODO - add readFully method to RecordInputStream
for(int i=0; i< RESERVED_FIELD_LEN; i++) {
* AFTER the last Ptg in the expression.
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
*/
- public void readTokenValues(RecordInputStream in) {
+ public void readTokenValues(LittleEndianInput in) {
int nColumns = in.readUByte();
short nRows = in.readShort();
//The token_1_columns and token_2_rows do not follow the documentation.
if (token_3_arrayValues == null) {
sb.append(" #values#uninitialised#\n");
} else {
- sb.append(" ").append(formatAsString());
+ sb.append(" ").append(toFormulaString());
}
return sb.toString();
}
return rowIx * token_1_columns + colIx;
}
- public void writeBytes(byte[] data, int offset) {
-
- LittleEndian.putByte(data, offset + 0, sid + getPtgClass());
- System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.write(field_1_reserved);
}
- public int writeTokenValueBytes(byte[] data, int offset) {
+ public int writeTokenValueBytes(LittleEndianOutput out) {
- LittleEndian.putByte(data, offset + 0, token_1_columns-1);
- LittleEndian.putUShort(data, offset + 1, token_2_rows-1);
- ConstantValueParser.encode(data, offset + 3, token_3_arrayValues);
+ out.writeByte(token_1_columns-1);
+ out.writeShort(token_2_rows-1);
+ ConstantValueParser.encode(out, token_3_arrayValues);
return 3 + ConstantValueParser.getEncodedSize(token_3_arrayValues);
}
+ ConstantValueParser.getEncodedSize(token_3_arrayValues);
}
- public String formatAsString() { // TODO - fold into toFormulaString
+ public String toFormulaString() {
StringBuffer b = new StringBuffer();
b.append("{");
for (int y=0;y<getRowCount();y++) {
b.append("}");
return b.toString();
}
- public String toFormulaString() {
- return formatAsString();
- }
private static String getConstantText(Object o) {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* "Special Attributes"
_chooseFuncOffset = -1;
}
- public AttrPtg(RecordInputStream in)
+ public AttrPtg(LittleEndianInput in)
{
field_1_options = in.readByte();
field_2_data = in.readShort();
return sb.toString();
}
- public void writeBytes(byte [] array, int offset)
- {
- LittleEndian.putByte(array, offset+0, sid);
- LittleEndian.putByte(array, offset+1, field_1_options);
- LittleEndian.putShort(array,offset+2, field_2_data);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeByte(field_1_options);
+ out.writeShort(field_2_data);
int[] jt = _jumpTable;
if (jt != null) {
- int joff = offset+4;
for (int i = 0; i < jt.length; i++) {
- LittleEndian.putUShort(array, joff, jt[i]);
- joff+=2;
+ out.writeShort(jt[i]);
}
- LittleEndian.putUShort(array, joff, _chooseFuncOffset);
+ out.writeShort(_chooseFuncOffset);
}
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
- * Boolean (boolean)
- * Stores a (java) boolean value in a formula.
+ * Boolean (boolean) Stores a (java) boolean value in a formula.
+ *
* @author Paul Krause (pkrause at soundbite dot com)
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class BoolPtg extends ScalarConstantPtg {
- public final static int SIZE = 2;
- public final static byte sid = 0x1d;
- private final boolean _value;
-
- public BoolPtg(RecordInputStream in) {
- _value = (in.readByte() == 1);
- }
-
- public BoolPtg(String formulaToken) {
- _value = (formulaToken.equalsIgnoreCase("TRUE"));
- }
-
- public boolean getValue() {
- return _value;
- }
-
- public void writeBytes(byte [] array, int offset) {
- array[ offset + 0 ] = sid;
- array[ offset + 1 ] = (byte) (_value ? 1 : 0);
- }
-
- public int getSize() {
- return SIZE;
- }
-
- public String toFormulaString() {
- return _value ? "TRUE" : "FALSE";
- }
+ public final static int SIZE = 2;
+ public final static byte sid = 0x1D;
+ private final boolean _value;
+
+ public BoolPtg(LittleEndianInput in) {
+ _value = (in.readByte() == 1);
+ }
+
+ public BoolPtg(String formulaToken) {
+ _value = (formulaToken.equalsIgnoreCase("TRUE"));
+ }
+
+ public boolean getValue() {
+ return _value;
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeByte(_value ? 1 : 0);
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ return _value ? "TRUE" : "FALSE";
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Title: Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
unused2 = 0;
}
- public DeletedArea3DPtg(RecordInputStream in) {
+ public DeletedArea3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readUShort();
unused1 = in.readInt();
unused2 = in.readInt();
public int getSize() {
return 11;
}
- public void writeBytes(byte[] data, int offset) {
- LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
- LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
- LittleEndian.putInt(data, 3 + offset, unused1);
- LittleEndian.putInt(data, 7 + offset, unused2);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_index_extern_sheet);
+ out.writeInt(unused1);
+ out.writeInt(unused2);
}
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Title: Deleted Reference 3D Ptg <P>
private final int unused1;
/** Creates new DeletedRef3DPtg */
- public DeletedRef3DPtg(RecordInputStream in) {
+ public DeletedRef3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readUShort();
unused1 = in.readInt();
}
public int getSize() {
return 7;
}
- public void writeBytes(byte[] data, int offset) {
- LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
- LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
- LittleEndian.putInt(data, 3 + offset, unused1);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_index_extern_sheet);
+ out.writeInt(unused1);
}
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
field_1_error_code = errorCode;
}
- public static ErrPtg read(RecordInputStream in) {
+ public static ErrPtg read(LittleEndianInput in) {
return valueOf(in.readByte());
}
- public void writeBytes(byte [] array, int offset)
- {
- array[offset] = (byte) (sid + getPtgClass());
- array[offset + 1] = (byte)field_1_error_code;
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeByte(field_1_error_code);
}
public String toFormulaString() {
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordFormatException;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
*
private final short field_1_first_row;
private final short field_2_first_col;
- public ExpPtg(RecordInputStream in)
+ public ExpPtg(LittleEndianInput in)
{
field_1_first_row = in.readShort();
field_2_first_col = in.readShort();
}
-
- public void writeBytes(byte [] array, int offset)
- {
- array[offset+0]= (byte) (sid);
- LittleEndian.putShort(array,offset+1,field_1_first_row);
- LittleEndian.putShort(array,offset+3,field_2_first_col);
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_first_row);
+ out.writeShort(field_2_first_col);
}
public int getSize()
{
return SIZE;
}
-
+
public short getRow() {
return field_1_first_row;
}
public short getColumn() {
return field_2_first_col;
- }
+ }
public String toFormulaString()
{
throw new RecordFormatException("Coding Error: Expected ExpPtg to be converted from Shared to Non-Shared Formula by ValueRecordsAggregate, but it wasn't");
}
-
+
public String toString()
{
StringBuffer buffer = new StringBuffer("[Array Formula or Shared Formula]\n");
buffer.append("row = ").append(getRow()).append("\n");
buffer.append("col = ").append(getColumn()).append("\n");
return buffer.toString();
- }
+ }
}
==================================================================== */
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* @author aviks
/**Creates new function pointer from a byte array
* usually called while reading an excel file.
*/
- public FuncPtg(RecordInputStream in) {
+ public FuncPtg(LittleEndianInput in) {
//field_1_num_args = data[ offset + 0 ];
field_2_fnc_index = in.readShort();
paramClass = fm.getParameterClassCodes();
}
- public void writeBytes(byte[] array, int offset) {
- array[offset+0]= (byte) (sid + getPtgClass());
- LittleEndian.putShort(array,offset+1,field_2_fnc_index);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_2_fnc_index);
}
public int getNumberOfOperands() {
==================================================================== */
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
*
/**Creates new function pointer from a byte array
* usually called while reading an excel file.
*/
- public FuncVarPtg(RecordInputStream in) {
+ public FuncVarPtg(LittleEndianInput in) {
field_1_num_args = in.readByte();
field_2_fnc_index = in.readShort();
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(field_2_fnc_index);
}
}
- public void writeBytes(byte[] array, int offset) {
- array[offset+0]=(byte) (sid + getPtgClass());
- array[offset+1]=field_1_num_args;
- LittleEndian.putShort(array,offset+2,field_2_fnc_index);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeByte(field_1_num_args);
+ out.writeShort(field_2_fnc_index);
}
public int getNumberOfOperands() {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
- * Integer (unsigned short integer)
- * Stores an unsigned short value (java int) in a formula
- * @author Andrew C. Oliver (acoliver at apache dot org)
+ * Integer (unsigned short integer) Stores an unsigned short value (java int) in
+ * a formula
+ *
+ * @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class IntPtg extends ScalarConstantPtg {
- // 16 bit unsigned integer
- private static final int MIN_VALUE = 0x0000;
- private static final int MAX_VALUE = 0xFFFF;
-
- /**
- * Excel represents integers 0..65535 with the tInt token.
- * @return <code>true</code> if the specified value is within the range of values
- * <tt>IntPtg</tt> can represent.
- */
- public static boolean isInRange(int i) {
- return i>=MIN_VALUE && i <=MAX_VALUE;
- }
+ // 16 bit unsigned integer
+ private static final int MIN_VALUE = 0x0000;
+ private static final int MAX_VALUE = 0xFFFF;
- public final static int SIZE = 3;
- public final static byte sid = 0x1e;
- private final int field_1_value;
-
- public IntPtg(RecordInputStream in) {
- this(in.readUShort());
- }
+ /**
+ * Excel represents integers 0..65535 with the tInt token.
+ *
+ * @return <code>true</code> if the specified value is within the range of values
+ * <tt>IntPtg</tt> can represent.
+ */
+ public static boolean isInRange(int i) {
+ return i >= MIN_VALUE && i <= MAX_VALUE;
+ }
- public IntPtg(int value) {
- if(!isInRange(value)) {
- throw new IllegalArgumentException("value is out of range: " + value);
- }
- field_1_value = value;
- }
+ public final static int SIZE = 3;
+ public final static byte sid = 0x1e;
+ private final int field_1_value;
- public int getValue() {
- return field_1_value;
- }
+ public IntPtg(LittleEndianInput in) {
+ this(in.readUShort());
+ }
- public void writeBytes(byte [] array, int offset) {
- array[ offset + 0 ] = sid;
- LittleEndian.putUShort(array, offset + 1, getValue());
- }
+ public IntPtg(int value) {
+ if (!isInRange(value)) {
+ throw new IllegalArgumentException("value is out of range: " + value);
+ }
+ field_1_value = value;
+ }
- public int getSize() {
- return SIZE;
- }
+ public int getValue() {
+ return field_1_value;
+ }
- public String toFormulaString() {
- return String.valueOf(getValue());
- }
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(getValue());
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ return String.valueOf(getValue());
+ }
}
package org.apache.poi.hssf.record.formula;
+import org.apache.poi.util.LittleEndianOutput;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public final class IntersectionPtg extends OperationPtg {
- public final static byte sid = 0x0f;
+ public final static byte sid = 0x0f;
- public static final OperationPtg instance = new IntersectionPtg();
+ public static final OperationPtg instance = new IntersectionPtg();
- private IntersectionPtg() {
- // enforce singleton
- }
+ private IntersectionPtg() {
+ // enforce singleton
+ }
- public final boolean isBaseToken() {
- return true;
- }
+ public final boolean isBaseToken() {
+ return true;
+ }
- public int getSize()
- {
- return 1;
- }
+ public int getSize() {
+ return 1;
+ }
- public void writeBytes( byte[] array, int offset )
- {
- array[ offset + 0 ] = sid;
- }
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ }
- /** Implementation of method from Ptg */
- public String toFormulaString()
- {
- return " ";
- }
+ public String toFormulaString() {
+ return " ";
+ }
+ public String toFormulaString(String[] operands) {
+ StringBuffer buffer = new StringBuffer();
- /** implementation of method from OperationsPtg*/
- public String toFormulaString(String[] operands)
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append(operands[ 0 ]);
- buffer.append(" ");
- buffer.append(operands[ 1 ]);
- return buffer.toString();
- }
-
- public int getNumberOfOperands()
- {
- return 2;
- }
+ buffer.append(operands[0]);
+ buffer.append(" ");
+ buffer.append(operands[1]);
+ return buffer.toString();
+ }
+ public int getNumberOfOperands() {
+ return 2;
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public class MemAreaPtg extends OperandPtg {
- public final static short sid = 0x26;
- private final static int SIZE = 7;
- private int field_1_reserved;
- private short field_2_subex_len;
-
- /** Creates new MemAreaPtg */
-
- public MemAreaPtg()
- {
- }
-
- public MemAreaPtg(RecordInputStream in)
- {
- field_1_reserved = in.readInt();
- field_2_subex_len = in.readShort();
- }
-
- public void setReserved(int res)
- {
- field_1_reserved = res;
- }
-
- public int getReserved()
- {
- return field_1_reserved;
- }
-
- public void setSubexpressionLength(short subexlen)
- {
- field_2_subex_len = subexlen;
- }
-
- public short getSubexpressionLength()
- {
- return field_2_subex_len;
- }
-
- public void writeBytes(byte [] array, int offset)
- {
- array[offset] = (byte) (sid + getPtgClass());
- LittleEndian.putInt(array, offset + 1, field_1_reserved);
- LittleEndian.putShort(array, offset + 5, field_2_subex_len);
- }
-
- public int getSize()
- {
- return SIZE;
- }
-
- public String toFormulaString()
- {
- return ""; // TODO: Not sure how to format this. -- DN
- }
-
- public byte getDefaultOperandClass() {
- return Ptg.CLASS_VALUE;
- }
+ public final static short sid = 0x26;
+ private final static int SIZE = 7;
+ private final int field_1_reserved;
+ private final int field_2_subex_len;
+
+ /** Creates new MemAreaPtg */
+
+ public MemAreaPtg(int subexLen) {
+ field_1_reserved = 0;
+ field_2_subex_len = subexLen;
+ }
+
+ public MemAreaPtg(LittleEndianInput in) {
+ field_1_reserved = in.readInt();
+ field_2_subex_len = in.readShort();
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeInt(field_1_reserved);
+ out.writeShort(field_2_subex_len);
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ return ""; // TODO: Not sure how to format this. -- DN
+ }
+
+ public byte getDefaultOperandClass() {
+ return Ptg.CLASS_VALUE;
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
- *
- * @author andy
+ *
+ * @author andy
* @author Jason Height (jheight at chariot dot net dot au)
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
-
-public final class MemErrPtg extends MemAreaPtg {
- public final static short sid = 0x27;
-
- /** Creates new MemErrPtg */
-
- public MemErrPtg()
- {
- }
-
- public MemErrPtg(RecordInputStream in) {
- super(in);
- }
-
- public void writeBytes(byte [] array, int offset) {
- super.writeBytes(array, offset);
- array[offset] = (byte) (sid + getPtgClass());
- }
-
- public String toFormulaString()
- {
- return "ERR#";
- }
+public final class MemErrPtg extends OperandPtg {
+ public final static short sid = 0x27;
+ private final static int SIZE = 7;
+ private int field_1_reserved;
+ private short field_2_subex_len;
+
+ public MemErrPtg(LittleEndianInput in) {
+ field_1_reserved = in.readInt();
+ field_2_subex_len = in.readShort();
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeInt(field_1_reserved);
+ out.writeShort(field_2_subex_len);
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ return "ERR#";
+ }
+
+ public byte getDefaultOperandClass() {
+ return Ptg.CLASS_VALUE;
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* @author Glen Stampoultzis (glens at apache.org)
*/
public final class MemFuncPtg extends OperandPtg {
- public final static byte sid = 0x29;
- private final int field_1_len_ref_subexpression;
+ public final static byte sid = 0x29;
+ private final int field_1_len_ref_subexpression;
- /**Creates new function pointer from a byte array
- * usually called while reading an excel file.
- */
- public MemFuncPtg(RecordInputStream in) {
- this(in.readUShort());
- }
+ /**
+ * Creates new function pointer from a byte array usually called while
+ * reading an excel file.
+ */
+ public MemFuncPtg(LittleEndianInput in) {
+ this(in.readUShort());
+ }
- public MemFuncPtg(int subExprLen) {
- field_1_len_ref_subexpression = subExprLen;
+ public MemFuncPtg(int subExprLen) {
+ field_1_len_ref_subexpression = subExprLen;
}
- public int getSize()
- {
- return 3;
- }
+ public int getSize() {
+ return 3;
+ }
- public void writeBytes( byte[] array, int offset )
- {
- array[offset + 0] = sid ;
- LittleEndian.putUShort( array, offset + 1, field_1_len_ref_subexpression );
- }
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_len_ref_subexpression);
+ }
- public String toFormulaString()
- {
- return "";
- }
+ public String toFormulaString() {
+ return "";
+ }
- public byte getDefaultOperandClass()
- {
- return Ptg.CLASS_REF;
- }
+ public byte getDefaultOperandClass() {
+ return Ptg.CLASS_REF;
+ }
- public int getNumberOfOperands()
- {
- return field_1_len_ref_subexpression;
- }
+ public int getNumberOfOperands() {
+ return field_1_len_ref_subexpression;
+ }
- public int getLenRefSubexpression()
- {
- return field_1_len_ref_subexpression;
- }
+ public int getLenRefSubexpression() {
+ return field_1_len_ref_subexpression;
+ }
}
\ No newline at end of file
package org.apache.poi.hssf.record.formula;
+import org.apache.poi.util.LittleEndianOutput;
+
/**
* Missing Function Arguments
- *
+ *
* Avik Sengupta <avik at apache.org>
+ *
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class MissingArgPtg extends ScalarConstantPtg {
-
- private final static int SIZE = 1;
- public final static byte sid = 0x16;
-
- public static final Ptg instance = new MissingArgPtg();
-
- private MissingArgPtg() {
- // enforce singleton
- }
-
- public void writeBytes(byte [] array, int offset) {
- array[ offset + 0 ] = sid;
- }
-
- public int getSize() {
- return SIZE;
- }
-
- public String toFormulaString() {
- return " ";
- }
+
+ private final static int SIZE = 1;
+ public final static byte sid = 0x16;
+
+ public static final Ptg instance = new MissingArgPtg();
+
+ private MissingArgPtg() {
+ // enforce singleton
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ return " ";
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
- *
- * @author andy
+ *
+ * @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class NamePtg extends OperandPtg implements WorkbookDependentFormula {
- public final static short sid = 0x23;
- private final static int SIZE = 5;
- /** one-based index to defined name record */
- private int field_1_label_index;
- private short field_2_zero; // reserved must be 0
+ public final static short sid = 0x23;
+ private final static int SIZE = 5;
+ /** one-based index to defined name record */
+ private int field_1_label_index;
+ private short field_2_zero; // reserved must be 0
- /**
- * @param nameIndex zero-based index to name within workbook
- */
- public NamePtg(int nameIndex) {
- field_1_label_index = 1+nameIndex; // convert to 1-based
- }
+ /**
+ * @param nameIndex zero-based index to name within workbook
+ */
+ public NamePtg(int nameIndex) {
+ field_1_label_index = 1 + nameIndex; // convert to 1-based
+ }
- /** Creates new NamePtg */
+ /** Creates new NamePtg */
- public NamePtg(RecordInputStream in) {
- field_1_label_index = in.readShort();
- field_2_zero = in.readShort();
- }
-
- /**
- * @return zero based index to a defined name record in the LinkTable
- */
- public int getIndex() {
- return field_1_label_index-1; // convert to zero based
- }
+ public NamePtg(LittleEndianInput in) {
+ field_1_label_index = in.readShort();
+ field_2_zero = in.readShort();
+ }
- public void writeBytes(byte [] array, int offset) {
- LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
- LittleEndian.putUShort(array, offset + 1, field_1_label_index);
- LittleEndian.putUShort(array, offset + 3, field_2_zero);
- }
+ /**
+ * @return zero based index to a defined name record in the LinkTable
+ */
+ public int getIndex() {
+ return field_1_label_index - 1; // convert to zero based
+ }
- public int getSize() {
- return SIZE;
- }
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_label_index);
+ out.writeShort(field_2_zero);
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString(FormulaRenderingWorkbook book) {
+ return book.getNameText(this);
+ }
- public String toFormulaString(FormulaRenderingWorkbook book)
- {
- return book.getNameText(this);
- }
public String toFormulaString() {
throw new RuntimeException("3D references need a workbook to determine formula text");
}
-
- public byte getDefaultOperandClass() {
+
+ public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
*
this(sheetRefIndex, nameIndex + 1, 0);
}
- public NameXPtg(RecordInputStream in) {
+ public NameXPtg(LittleEndianInput in) {
this(in.readUShort(), in.readUShort(), in.readUShort());
}
- public void writeBytes(byte[] array, int offset) {
- LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
- LittleEndian.putUShort(array, offset + 1, _sheetRefIndex);
- LittleEndian.putUShort(array, offset + 3, _nameNumber);
- LittleEndian.putUShort(array, offset + 5, _reserved);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(_sheetRefIndex);
+ out.writeShort(_nameNumber);
+ out.writeShort(_reserved);
}
public int getSize() {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
- * Number
- * Stores a floating point value in a formula
- * value stored in a 8 byte field using IEEE notation
- * @author Avik Sengupta
+ * Number Stores a floating point value in a formula value stored in a 8 byte
+ * field using IEEE notation
+ *
+ * @author Avik Sengupta
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class NumberPtg extends ScalarConstantPtg {
- public final static int SIZE = 9;
- public final static byte sid = 0x1f;
- private final double field_1_value;
-
- /** Create a NumberPtg from a byte array read from disk */
- public NumberPtg(RecordInputStream in) {
- this(in.readDouble());
- }
-
- /** Create a NumberPtg from a string representation of the number
- * Number format is not checked, it is expected to be validated in the parser
- * that calls this method.
- * @param value : String representation of a floating point number
- */
- public NumberPtg(String value) {
- this(Double.parseDouble(value));
- }
-
- public NumberPtg(double value) {
- field_1_value = value;
- }
-
- public double getValue() {
- return field_1_value;
- }
+ public final static int SIZE = 9;
+ public final static byte sid = 0x1f;
+ private final double field_1_value;
- public void writeBytes(byte [] array, int offset) {
- array[ offset + 0 ] = sid;
- LittleEndian.putDouble(array, offset + 1, getValue());
- }
+ public NumberPtg(LittleEndianInput in) {
+ this(in.readDouble());
+ }
- public int getSize() {
- return SIZE;
- }
+ /**
+ * Create a NumberPtg from a string representation of the number Number
+ * format is not checked, it is expected to be validated in the parser that
+ * calls this method.
+ *
+ * @param value String representation of a floating point number
+ */
+ public NumberPtg(String value) {
+ this(Double.parseDouble(value));
+ }
- public String toFormulaString() {
- // TODO - java's rendering of double values is not quite same as excel's
- // Maybe use HSSFDataFormatter?
- return String.valueOf(field_1_value);
- }
+ public NumberPtg(double value) {
+ field_1_value = value;
+ }
+
+ public double getValue() {
+ return field_1_value;
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeDouble(getValue());
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ // TODO - java's rendering of double values is not quite same as excel's
+ return String.valueOf(field_1_value);
+ }
}
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.record.formula;
+import org.apache.poi.util.LittleEndianOutput;
/**
- * While formula tokens are stored in RPN order and thus do not need parenthesis for
- * precedence reasons, Parenthesis tokens ARE written to ensure that user entered
- * parenthesis are displayed as-is on reading back
- *
- * Avik Sengupta <lists@aviksengupta.com>
- * Andrew C. Oliver (acoliver at apache dot org)
+ * While formula tokens are stored in RPN order and thus do not need parenthesis
+ * for precedence reasons, Parenthesis tokens ARE written to ensure that user
+ * entered parenthesis are displayed as-is on reading back
+ *
+ * Avik Sengupta <lists@aviksengupta.com> Andrew C. Oliver (acoliver at
+ * apache dot org)
+ *
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class ParenthesisPtg extends ControlPtg {
-
- private final static int SIZE = 1;
- public final static byte sid = 0x15;
-
- public static final ControlPtg instance = new ParenthesisPtg();
- private ParenthesisPtg() {
- // enforce singleton
- }
-
- public void writeBytes(byte [] array, int offset)
- {
- array[ offset + 0 ] = sid;
- }
-
- public int getSize()
- {
- return SIZE;
- }
-
- public String toFormulaString()
- {
- return "()";
- }
-
-
- public String toFormulaString(String[] operands) {
- return "("+operands[0]+")";
- }
+
+ private final static int SIZE = 1;
+ public final static byte sid = 0x15;
+
+ public static final ControlPtg instance = new ParenthesisPtg();
+
+ private ParenthesisPtg() {
+ // enforce singleton
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString() {
+ return "()";
+ }
+
+ public String toFormulaString(String[] operands) {
+ return "(" + operands[0] + ")";
+ }
}
import java.util.ArrayList;
import java.util.List;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
/**
* Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
* Extra data (beyond <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s are present.
*/
- public static Ptg[] readTokens(int size, RecordInputStream in) {
+ public static Ptg[] readTokens(int size, LittleEndianInput in) {
List temp = new ArrayList(4 + size / 2);
int pos = 0;
List arrayPtgs = null;
while (pos < size) {
- Ptg ptg = Ptg.createPtg( in );
+ Ptg ptg = Ptg.createPtg(in);
if (ptg instanceof ArrayPtg) {
if (arrayPtgs == null) {
arrayPtgs = new ArrayList(5);
return toPtgArray(temp);
}
- public static Ptg createPtg(RecordInputStream in) {
+ public static Ptg createPtg(LittleEndianInput in) {
byte id = in.readByte();
if (id < 0x20) {
return retval;
}
- private static Ptg createClassifiedPtg(byte id, RecordInputStream in) {
+ private static Ptg createClassifiedPtg(byte id, LittleEndianInput in) {
int baseId = id & 0x1F | 0x20;
Integer.toHexString(id) + " (" + ( int ) id + ")");
}
- private static Ptg createBasePtg(byte id, RecordInputStream in) {
+ private static Ptg createBasePtg(byte id, LittleEndianInput in) {
switch(id) {
- case 0x00: return new UnknownPtg(); // TODO - not a real Ptg
+ case 0x00: return new UnknownPtg(id); // TODO - not a real Ptg
case ExpPtg.sid: return new ExpPtg(in); // 0x01
case TblPtg.sid: return new TblPtg(in); // 0x02
case AddPtg.sid: return AddPtg.instance; // 0x03
* @return number of bytes written
*/
public static int serializePtgs(Ptg[] ptgs, byte[] array, int offset) {
- int pos = 0;
- int size = ptgs.length;
+ int nTokens = ptgs.length;
+
+ LittleEndianByteArrayOutputStream out = new LittleEndianByteArrayOutputStream(array, offset);
List arrayPtgs = null;
- for (int k = 0; k < size; k++) {
+ for (int k = 0; k < nTokens; k++) {
Ptg ptg = ptgs[k];
- ptg.writeBytes(array, pos + offset);
+ ptg.write(out);
if (ptg instanceof ArrayPtg) {
if (arrayPtgs == null) {
arrayPtgs = new ArrayList(5);
}
arrayPtgs.add(ptg);
- pos += ArrayPtg.PLAIN_TOKEN_SIZE;
- } else {
- pos += ptg.getSize();
}
}
if (arrayPtgs != null) {
for (int i=0;i<arrayPtgs.size();i++) {
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
- pos += p.writeTokenValueBytes(array, pos + offset);
+ p.writeTokenValueBytes(out);
}
}
- return pos;
+ return out.getWriteIndex() - offset;
}
/**
*/
// public abstract int getDataSize();
- public final byte[] getBytes()
- {
- int size = getSize();
- byte[] bytes = new byte[ size ];
-
- writeBytes(bytes, 0);
- return bytes;
- }
- /** write this Ptg to a byte array*/
- public abstract void writeBytes(byte [] array, int offset);
-
- public void write(LittleEndianOutput out) {
- out.write(getBytes()); // TODO - optimise - just a hack for the moment
- }
+ public abstract void write(LittleEndianOutput out);
/**
* return a string representation of this token alone
*/
public abstract String toFormulaString();
- /**
- * dump a debug representation (hexdump) to a string
- */
- public final String toDebugString() {
- byte[] ba = new byte[getSize()];
- writeBytes(ba,0);
- try {
- return HexDump.dump(ba,0,0);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
/** Overridden toString method to ensure object hash is not printed.
* This helps get rid of gratuitous diffs when comparing two dumps
package org.apache.poi.hssf.record.formula;
+import org.apache.poi.util.LittleEndianOutput;
+
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
return SIZE;
}
- public void writeBytes( byte[] array, int offset )
- {
- array[ offset + 0 ] = sid;
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
}
public String toFormulaString()
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* @author Josh Micich
*/
abstract class Ref2DPtgBase extends RefPtgBase {
- private final static int SIZE = 5;
+ private final static int SIZE = 5;
- /**
- * Takes in a String representation of a cell reference and fills out the
- * numeric fields.
- */
- protected Ref2DPtgBase(String cellref) {
- super(cellref);
- }
+ /**
+ * Takes in a String representation of a cell reference and fills out the
+ * numeric fields.
+ */
+ protected Ref2DPtgBase(String cellref) {
+ super(cellref);
+ }
- protected Ref2DPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
- setRow(row);
- setColumn(column);
- setRowRelative(isRowRelative);
- setColRelative(isColumnRelative);
- }
+ protected Ref2DPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
+ setRow(row);
+ setColumn(column);
+ setRowRelative(isRowRelative);
+ setColRelative(isColumnRelative);
+ }
- protected Ref2DPtgBase(RecordInputStream in) {
- readCoordinates(in);
- }
- public final void writeBytes(byte [] array, int offset) {
- LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
- writeCoordinates(array, offset+1);
- }
- public final String toFormulaString() {
- return formatReferenceAsString();
- }
+ protected Ref2DPtgBase(LittleEndianInput in) {
+ readCoordinates(in);
+ }
+
+ public void write(LittleEndianOutput out) {
+ out.writeByte(getSid() + getPtgClass());
+ writeCoordinates(out);
+ }
+
+ public final String toFormulaString() {
+ return formatReferenceAsString();
+ }
protected abstract byte getSid();
- public final int getSize() {
- return SIZE;
- }
- public final String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append(getClass().getName());
- sb.append(" [");
- sb.append(formatReferenceAsString());
- sb.append("]");
- return sb.toString();
- }
+
+ public final int getSize() {
+ return SIZE;
+ }
+
+ public final String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append(" [");
+ sb.append(formatReferenceAsString());
+ sb.append("]");
+ return sb.toString();
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.ExternSheetReferenceToken;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.WorkbookDependentFormula;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Title: Reference 3D Ptg <P>
/** Creates new AreaPtg */
public Ref3DPtg() {}
- public Ref3DPtg(RecordInputStream in) {
+ public Ref3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readShort();
readCoordinates(in);
}
return sb.toString();
}
- public void writeBytes(byte [] array, int offset) {
- LittleEndian.putByte(array, 0 + offset, sid + getPtgClass());
- LittleEndian.putUShort(array, 1 + offset, getExternSheetIndex());
- writeCoordinates(array, offset + 3);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(getExternSheetIndex());
+ writeCoordinates(out);
}
public int getSize() {
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* RefError - handles deleted cell reference
public RefErrorPtg() {
field_1_reserved = 0;
}
- public RefErrorPtg(RecordInputStream in) {
+ public RefErrorPtg(LittleEndianInput in) {
field_1_reserved = in.readInt();
}
return getClass().getName();
}
- public void writeBytes(byte [] array, int offset) {
- LittleEndian.putByte(array, offset+0, sid + getPtgClass());
- LittleEndian.putInt(array,offset+1,field_1_reserved);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeInt(field_1_reserved);
}
public int getSize()
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
/**
* RefNPtg
public final class RefNPtg extends Ref2DPtgBase {
public final static byte sid = 0x2C;
- public RefNPtg(RecordInputStream in) {
+ public RefNPtg(LittleEndianInput in) {
super(in);
}
\r
package org.apache.poi.hssf.record.formula;\r
\r
-import org.apache.poi.hssf.record.RecordInputStream;\r
+import org.apache.poi.util.LittleEndianInput;\r
\r
/**\r
* ReferencePtg - handles references (such as A1, A2, IA4)\r
super(row, column, isRowRelative, isColumnRelative);\r
}\r
\r
- public RefPtg(RecordInputStream in) {\r
+ public RefPtg(LittleEndianInput in) {\r
super(in);\r
}\r
\r
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* ReferencePtgBase - handles references (such as A1, A2, IA4)
- * @author Andrew C. Oliver (acoliver@apache.org)
+ *
+ * @author Andrew C. Oliver (acoliver@apache.org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public abstract class RefPtgBase extends OperandPtg {
- private final static int MAX_ROW_NUMBER = 65536;
-
- /** The row index - zero based unsigned 16 bit value */
- private int field_1_row;
- /** Field 2
- * - lower 8 bits is the zero based unsigned byte column index
- * - bit 16 - isRowRelative
- * - bit 15 - isColumnRelative
- */
- private int field_2_col;
- private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
- private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
- private static final BitField column = BitFieldFactory.getInstance(0x00FF);
-
- protected RefPtgBase() {
- //Required for clone methods
- }
-
- /**
- * Takes in a String representation of a cell reference and fills out the
- * numeric fields.
- */
- protected RefPtgBase(String cellref) {
- CellReference c= new CellReference(cellref);
- setRow(c.getRow());
- setColumn(c.getCol());
- setColRelative(!c.isColAbsolute());
- setRowRelative(!c.isRowAbsolute());
- }
-
- protected RefPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
- setRow(row);
- setColumn(column);
- setRowRelative(isRowRelative);
- setColRelative(isColumnRelative);
- }
-
- protected final void readCoordinates(RecordInputStream in) {
- field_1_row = in.readUShort();
- field_2_col = in.readUShort();
- }
- protected final void writeCoordinates(byte[] array, int offset) {
- LittleEndian.putUShort(array, offset + 0, field_1_row);
- LittleEndian.putUShort(array, offset + 2, field_2_col);
- }
-
- public final void setRow(int row) {
- if(row < 0 || row >= MAX_ROW_NUMBER) {
- throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + MAX_ROW_NUMBER);
- }
- field_1_row = row;
- }
-
- /**
- * @return the row number as an int, between 0 and 65535
- */
- public final int getRow(){
- return field_1_row;
- }
-
- public final boolean isRowRelative() {
- return rowRelative.isSet(field_2_col);
- }
-
- public final void setRowRelative(boolean rel) {
- field_2_col=rowRelative.setBoolean(field_2_col,rel);
- }
-
- public final boolean isColRelative() {
- return colRelative.isSet(field_2_col);
- }
-
- public final void setColRelative(boolean rel) {
- field_2_col=colRelative.setBoolean(field_2_col,rel);
- }
-
- public final void setColumn(int col) {
- if(col < 0 || col >= 0x100) {
- throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
- }
- field_2_col = column.setValue(field_2_col, col);
- }
-
- public final int getColumn() {
- return column.getValue(field_2_col);
- }
- protected final String formatReferenceAsString() {
- // Only make cell references as needed. Memory is an issue
- CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative());
- return cr.formatAsString();
- }
-
- public final byte getDefaultOperandClass() {
- return Ptg.CLASS_REF;
- }
+ private final static int MAX_ROW_NUMBER = 65536;
+
+ /** The row index - zero based unsigned 16 bit value */
+ private int field_1_row;
+ /**
+ * Field 2 - lower 8 bits is the zero based unsigned byte column index - bit
+ * 16 - isRowRelative - bit 15 - isColumnRelative
+ */
+ private int field_2_col;
+ private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
+ private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
+ private static final BitField column = BitFieldFactory.getInstance(0x00FF);
+
+ protected RefPtgBase() {
+ // Required for clone methods
+ }
+
+ /**
+ * Takes in a String representation of a cell reference and fills out the
+ * numeric fields.
+ */
+ protected RefPtgBase(String cellref) {
+ CellReference c = new CellReference(cellref);
+ setRow(c.getRow());
+ setColumn(c.getCol());
+ setColRelative(!c.isColAbsolute());
+ setRowRelative(!c.isRowAbsolute());
+ }
+
+ protected RefPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
+ setRow(row);
+ setColumn(column);
+ setRowRelative(isRowRelative);
+ setColRelative(isColumnRelative);
+ }
+
+ protected final void readCoordinates(LittleEndianInput in) {
+ field_1_row = in.readUShort();
+ field_2_col = in.readUShort();
+ }
+
+ protected final void writeCoordinates(LittleEndianOutput out) {
+ out.writeShort(field_1_row);
+ out.writeShort(field_2_col);
+ }
+
+ public final void setRow(int rowIndex) {
+ if (rowIndex < 0 || rowIndex >= MAX_ROW_NUMBER) {
+ throw new IllegalArgumentException("rowIndex must be between 0 and " + MAX_ROW_NUMBER);
+ }
+ field_1_row = rowIndex;
+ }
+
+ /**
+ * @return the row number as an int, between 0 and 65535
+ */
+ public final int getRow() {
+ return field_1_row;
+ }
+
+ public final boolean isRowRelative() {
+ return rowRelative.isSet(field_2_col);
+ }
+
+ public final void setRowRelative(boolean rel) {
+ field_2_col = rowRelative.setBoolean(field_2_col, rel);
+ }
+
+ public final boolean isColRelative() {
+ return colRelative.isSet(field_2_col);
+ }
+
+ public final void setColRelative(boolean rel) {
+ field_2_col = colRelative.setBoolean(field_2_col, rel);
+ }
+
+ public final void setColumn(int col) {
+ if (col < 0 || col >= 0x100) {
+ throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
+ }
+ field_2_col = column.setValue(field_2_col, col);
+ }
+
+ public final int getColumn() {
+ return column.getValue(field_2_col);
+ }
+
+ protected final String formatReferenceAsString() {
+ // Only make cell references as needed. Memory is an issue
+ CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative());
+ return cr.formatAsString();
+ }
+
+ public final byte getDefaultOperandClass() {
+ return Ptg.CLASS_REF;
+ }
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
/**
* @author Bernard Chesnoy
*/
public final class StringPtg extends ScalarConstantPtg {
- public final static int SIZE = 9;
- public final static byte sid = 0x17;
- private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
- /** the character (")used in formulas to delimit string literals */
+ public final static byte sid = 0x17;
+ /** the character (") used in formulas to delimit string literals */
private static final char FORMULA_DELIMITER = '"';
+ private final boolean _is16bitUnicode;
/**
* NOTE: OO doc says 16bit length, but BiffViewer says 8 Book says something
* totally different, so don't look there!
*/
- private final int field_1_length;
- private final byte field_2_options;
private final String field_3_string;
/** Create a StringPtg from a stream */
- public StringPtg(RecordInputStream in) {
- field_1_length = in.readUByte();
- field_2_options = in.readByte();
- if (fHighByte.isSet(field_2_options)) {
- field_3_string = in.readUnicodeLEString(field_1_length);
- } else {
- field_3_string = in.readCompressedUnicode(field_1_length);
- }
+ public StringPtg(LittleEndianInput in) {
+ int nChars = in.readUByte(); // Note - nChars is 8-bit
+ _is16bitUnicode = (in.readByte() & 0x01) != 0;
+ if (_is16bitUnicode) {
+ field_3_string = StringUtil.readUnicodeLE(in, nChars);
+ } else {
+ field_3_string = StringUtil.readCompressedUnicode(in, nChars);
+ }
}
/**
throw new IllegalArgumentException(
"String literals in formulas can't be bigger than 255 characters ASCII");
}
- field_2_options = (byte) fHighByte.setBoolean(0, StringUtil.hasMultibyte(value));
+ _is16bitUnicode = StringUtil.hasMultibyte(value);
field_3_string = value;
- field_1_length = value.length(); // for the moment, we support only ASCII strings in formulas we create
}
public String getValue() {
return field_3_string;
}
- public void writeBytes(byte[] array, int offset) {
- array[offset + 0] = sid;
- array[offset + 1] = (byte) field_1_length;
- array[offset + 2] = field_2_options;
- if (fHighByte.isSet(field_2_options)) {
- StringUtil.putUnicodeLE(getValue(), array, offset + 3);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeByte(field_3_string.length()); // Note - nChars is 8-bit
+ out.writeByte(_is16bitUnicode ? 0x01 : 0x00);
+ if (_is16bitUnicode) {
+ StringUtil.putUnicodeLE(field_3_string, out);
} else {
- StringUtil.putCompressedUnicode(getValue(), array, offset + 3);
+ StringUtil.putCompressedUnicode(field_3_string, out);
}
}
public int getSize() {
- if (fHighByte.isSet(field_2_options)) {
- return 2 * field_1_length + 3;
- } else {
- return field_1_length + 3;
- }
+ return 3 + field_3_string.length() * (_is16bitUnicode ? 2 : 1);
}
public String toFormulaString() {
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordFormatException;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* This ptg indicates a data table.
/** The column number of the upper left corner */
private final int field_2_first_col;
- public TblPtg(RecordInputStream in) {
+ public TblPtg(LittleEndianInput in) {
field_1_first_row = in.readUShort();
field_2_first_col = in.readUShort();
}
- public void writeBytes(byte [] array, int offset) {
- LittleEndian.putByte(array, offset+0, sid);
- LittleEndian.putUShort(array, offset+1, field_1_first_row);
- LittleEndian.putUShort(array, offset+3, field_2_first_col);
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
+ out.writeShort(field_1_first_row);
+ out.writeShort(field_2_first_col);
}
public int getSize() {
package org.apache.poi.hssf.record.formula;
+import org.apache.poi.util.LittleEndianOutput;
+
/**
* @author Glen Stampoultzis (glens at apache.org)
return 1;
}
- public void writeBytes( byte[] array, int offset )
- {
- array[ offset + 0 ] = sid;
+ public void write(LittleEndianOutput out) {
+ out.writeByte(sid + getPtgClass());
}
public String toFormulaString()
==================================================================== */
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianOutput;
/**
*
*/
public class UnknownPtg extends Ptg {
private short size = 1;
+ private final int _sid;
- /** Creates new UnknownPtg */
-
- public UnknownPtg()
- {
- }
-
- public UnknownPtg(RecordInputStream in) {
- // doesn't need anything
+ public UnknownPtg(int sid) {
+ _sid = sid;
}
public boolean isBaseToken() {
- return true;
+ return true;
}
- public void writeBytes(byte [] array, int offset)
- {
+ public void write(LittleEndianOutput out) {
+ out.writeByte(_sid);
}
public int getSize()
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
- return new UnknownPtg();
+ return this;
}
-
-
}
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianOutput;
/**
- * Common superclass of all value operators.
- * Subclasses include all unary and binary operators except for the reference operators (IntersectionPtg, RangePtg, UnionPtg)
+ * Common superclass of all value operators. Subclasses include all unary and
+ * binary operators except for the reference operators (IntersectionPtg,
+ * RangePtg, UnionPtg)
*
* @author Josh Micich
*/
public abstract class ValueOperatorPtg extends OperationPtg {
/**
- * All Operator <tt>Ptg</tt>s are base tokens (i.e. are not RVA classified)
+ * All Operator <tt>Ptg</tt>s are base tokens (i.e. are not RVA classified)
*/
public final boolean isBaseToken() {
return true;
return Ptg.CLASS_VALUE;
}
- public final void writeBytes(byte[] array, int offset) {
- array[offset + 0] = getSid();
+ public void write(LittleEndianOutput out) {
+ out.writeByte(getSid());
}
protected abstract byte getSid();
public final int getSize() {
return 1;
}
- public final String toFormulaString() {
- // TODO - prune this method out of the hierarchy
- throw new RuntimeException("toFormulaString(String[] operands) should be used for subclasses of OperationPtgs");
+
+ public final String toFormulaString() {
+ // TODO - prune this method out of the hierarchy
+ throw new RuntimeException("toFormulaString(String[] operands) should be used for subclasses of OperationPtgs");
}
}
if(sr == null) {
return null;
}
- if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
+ if(sr.isBuiltin()) {
return null;
}
return sr.getName();
if(sr == null) {
sr = workbook.createStyleRecord(index);
}
- if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
+ if(sr.isBuiltin()) {
throw new IllegalArgumentException("Unable to set user specified style names for built in styles!");
}
sr.setName(styleName);
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.filesystem;
-import java.io.*;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.poifs.storage.DataInputBlock;
+import org.apache.poi.util.LittleEndianInput;
/**
* This class provides methods to read a DocumentEntry managed by a
- * Filesystem instance.
+ * {@link POIFSFileSystem} instance.
*
* @author Marc Johnson (mjohnson at apache dot org)
*/
-
-public class DocumentInputStream
- extends InputStream
-{
-
- // current offset into the Document
- private int _current_offset;
-
- // current marked offset into the Document (used by mark and
- // reset)
- private int _marked_offset;
-
- // the Document's size
- private int _document_size;
-
- // have we been closed?
- private boolean _closed;
-
- // the actual Document
- private POIFSDocument _document;
-
- // buffer used to read one byte at a time
- private byte[] _tiny_buffer;
-
- // returned by read operations if we're at end of document
- static private final int EOD = -1;
-
- /**
- * Create an InputStream from the specified DocumentEntry
- *
- * @param document the DocumentEntry to be read
- *
- * @exception IOException if the DocumentEntry cannot be opened
- * (like, maybe it has been deleted?)
- */
-
- public DocumentInputStream(final DocumentEntry document)
- throws IOException
- {
- _current_offset = 0;
- _marked_offset = 0;
- _document_size = document.getSize();
- _closed = false;
- _tiny_buffer = null;
- if (document instanceof DocumentNode)
- {
- _document = (( DocumentNode ) document).getDocument();
- }
- else
- {
- throw new IOException("Cannot open internal document storage");
- }
- }
-
- /**
- * Create an InputStream from the specified Document
- *
- * @param document the Document to be read
- *
- * @exception IOException if the DocumentEntry cannot be opened
- * (like, maybe it has been deleted?)
- */
-
- public DocumentInputStream(final POIFSDocument document)
- throws IOException
- {
- _current_offset = 0;
- _marked_offset = 0;
- _document_size = document.getSize();
- _closed = false;
- _tiny_buffer = null;
- _document = document;
- }
-
- /**
- * Returns the number of bytes that can be read (or skipped over)
- * from this input stream without blocking by the next caller of a
- * method for this input stream. The next caller might be the same
- * thread or or another thread.
- *
- * @return the number of bytes that can be read from this input
- * stream without blocking.
- *
- * @exception IOException on error (such as the stream has been
- * closed)
- */
-
- public int available()
- throws IOException
- {
- dieIfClosed();
- return _document_size - _current_offset;
- }
-
- /**
- * Closes this input stream and releases any system resources
- * associated with the stream.
- *
- * @exception IOException
- */
-
- public void close()
- throws IOException
- {
- _closed = true;
- }
-
- /**
- * Marks the current position in this input stream. A subsequent
- * call to the reset method repositions this stream at the last
- * marked position so that subsequent reads re-read the same
- * bytes.
- * <p>
- * The readlimit arguments tells this input stream to allow that
- * many bytes to be read before the mark position gets
- * invalidated. This implementation, however, does not care.
- * <p>
- * The general contract of mark is that, if the method
- * markSupported returns true, the stream somehow remembers all
- * the bytes read after the call to mark and stands ready to
- * supply those same bytes again if and whenever the method reset
- * is called. However, the stream is not required to remember any
- * data at all if more than readlimit bytes are read from the
- * stream before reset is called. But this stream will.
- *
- * @param ignoredReadlimit the maximum limit of bytes that can be
- * read before the mark position becomes
- * invalid. Ignored by this
- * implementation.
- */
-
- public void mark(int ignoredReadlimit)
- {
- _marked_offset = _current_offset;
- }
-
- /**
- * Tests if this input stream supports the mark and reset methods.
- *
- * @return true
- */
-
- public boolean markSupported()
- {
- return true;
- }
-
- /**
- * Reads the next byte of data from the input stream. The value
- * byte is returned as an int in the range 0 to 255. If no byte is
- * available because the end of the stream has been reached, the
- * value -1 is returned. The definition of this method in
- * java.io.InputStream allows this method to block, but it won't.
- *
- * @return the next byte of data, or -1 if the end of the stream
- * is reached.
- *
- * @exception IOException
- */
-
- public int read()
- throws IOException
- {
- dieIfClosed();
- if (atEOD())
- {
- return EOD;
- }
- if (_tiny_buffer == null)
- {
- _tiny_buffer = new byte[ 1 ];
- }
- _document.read(_tiny_buffer, _current_offset++);
- return ((int)_tiny_buffer[ 0 ]) & 0x000000FF;
- }
-
- /**
- * Reads some number of bytes from the input stream and stores
- * them into the buffer array b. The number of bytes actually read
- * is returned as an integer. The definition of this method in
- * java.io.InputStream allows this method to block, but it won't.
- * <p>
- * If b is null, a NullPointerException is thrown. If the length
- * of b is zero, then no bytes are read and 0 is returned;
- * otherwise, there is an attempt to read at least one byte. If no
- * byte is available because the stream is at end of file, the
- * value -1 is returned; otherwise, at least one byte is read and
- * stored into b.
- * <p>
- * The first byte read is stored into element b[0], the next one
- * into b[1], and so on. The number of bytes read is, at most,
- * equal to the length of b. Let k be the number of bytes actually
- * read; these bytes will be stored in elements b[0] through
- * b[k-1], leaving elements b[k] through b[b.length-1] unaffected.
- * <p>
- * If the first byte cannot be read for any reason other than end
- * of file, then an IOException is thrown. In particular, an
- * IOException is thrown if the input stream has been closed.
- * <p>
- * The read(b) method for class InputStream has the same effect as:
- * <p>
- * <code>read(b, 0, b.length)</code>
- *
- * @param b the buffer into which the data is read.
- *
- * @return the total number of bytes read into the buffer, or -1
- * if there is no more data because the end of the stream
- * has been reached.
- *
- * @exception IOException
- * @exception NullPointerException
- */
-
- public int read(final byte [] b)
- throws IOException, NullPointerException
- {
- return read(b, 0, b.length);
- }
-
- /**
- * Reads up to len bytes of data from the input stream into an
- * array of bytes. An attempt is made to read as many as len
- * bytes, but a smaller number may be read, possibly zero. The
- * number of bytes actually read is returned as an integer.
- * <p>
- * The definition of this method in java.io.InputStream allows it
- * to block, but it won't.
- * <p>
- * If b is null, a NullPointerException is thrown.
- * <p>
- * If off is negative, or len is negative, or off+len is greater
- * than the length of the array b, then an
- * IndexOutOfBoundsException is thrown.
- * <p>
- * If len is zero, then no bytes are read and 0 is returned;
- * otherwise, there is an attempt to read at least one byte. If no
- * byte is available because the stream is at end of file, the
- * value -1 is returned; otherwise, at least one byte is read and
- * stored into b.
- * <p>
- * The first byte read is stored into element b[off], the next one
- * into b[off+1], and so on. The number of bytes read is, at most,
- * equal to len. Let k be the number of bytes actually read; these
- * bytes will be stored in elements b[off] through b[off+k-1],
- * leaving elements b[off+k] through b[off+len-1] unaffected.
- * <p>
- * In every case, elements b[0] through b[off] and elements
- * b[off+len] through b[b.length-1] are unaffected.
- * <p>
- * If the first byte cannot be read for any reason other than end
- * of file, then an IOException is thrown. In particular, an
- * IOException is thrown if the input stream has been closed.
- *
- * @param b the buffer into which the data is read.
- * @param off the start offset in array b at which the data is
- * written.
- * @param len the maximum number of bytes to read.
- *
- * @return the total number of bytes read into the buffer, or -1
- * if there is no more data because the end of the stream
- * has been reached.
- *
- * @exception IOException
- * @exception NullPointerException
- * @exception IndexOutOfBoundsException
- */
-
- public int read(final byte [] b, final int off, final int len)
- throws IOException, NullPointerException, IndexOutOfBoundsException
- {
- dieIfClosed();
- if (b == null)
- {
- throw new NullPointerException("buffer is null");
- }
- if ((off < 0) || (len < 0) || (b.length < (off + len)))
- {
- throw new IndexOutOfBoundsException(
- "can't read past buffer boundaries");
- }
- if (len == 0)
- {
- return 0;
- }
- if (atEOD())
- {
- return EOD;
- }
- int limit = Math.min(available(), len);
-
- if ((off == 0) && (limit == b.length))
- {
- _document.read(b, _current_offset);
- }
- else
- {
- byte[] buffer = new byte[ limit ];
-
- _document.read(buffer, _current_offset);
- System.arraycopy(buffer, 0, b, off, limit);
- }
- _current_offset += limit;
- return limit;
- }
-
- /**
- * Repositions this stream to the position at the time the mark
- * method was last called on this input stream.
- * <p>
- * The general contract of reset is:
- * <p>
- * <ul>
- * <li>
- * If the method markSupported returns true, then:
- * <ul>
- * <li>
- * If the method mark has not been called since the
- * stream was created, or the number of bytes read
- * from the stream since mark was last called is
- * larger than the argument to mark at that last
- * call, then an IOException might be thrown.
- * </li>
- * <li>
- * If such an IOException is not thrown, then the
- * stream is reset to a state such that all the
- * bytes read since the most recent call to mark
- * (or since the start of the file, if mark has not
- * been called) will be resupplied to subsequent
- * callers of the read method, followed by any
- * bytes that otherwise would have been the next
- * input data as of the time of the call to reset.
- * </li>
- * </ul>
- * </li>
- * <li>
- * If the method markSupported returns false, then:
- * <ul>
- * <li>
- * The call to reset may throw an IOException.
- * </li>
- * <li>
- * If an IOException is not thrown, then the
- * stream is reset to a fixed state that depends
- * on the particular type of the input and how it
- * was created. The bytes that will be supplied to
- * subsequent callers of the read method depend on
- * the particular type of the input stream.
- * </li>
- * </ul>
- * </li>
- * </ul>
- * <p>
- * All well and good ... this class's markSupported method returns
- * true and this method does not care whether you've called mark
- * at all, or whether you've exceeded the number of bytes
- * specified in the last call to mark. We're basically walking a
- * byte array ... mark and reset to your heart's content.
- */
-
- public void reset()
- {
- _current_offset = _marked_offset;
- }
-
- /**
- * Skips over and discards n bytes of data from this input
- * stream. The skip method may, for a variety of reasons, end up
- * skipping over some smaller number of bytes, possibly 0. This
- * may result from any of a number of conditions; reaching end of
- * file before n bytes have been skipped is only one
- * possibility. The actual number of bytes skipped is returned. If
- * n is negative, no bytes are skipped.
- *
- * @param n the number of bytes to be skipped.
- *
- * @return the actual number of bytes skipped.
- *
- * @exception IOException
- */
-
- public long skip(final long n)
- throws IOException
- {
- dieIfClosed();
- if (n < 0)
- {
- return 0;
- }
- int new_offset = _current_offset + ( int ) n;
-
- if (new_offset < _current_offset)
- {
-
- // wrap around in converting a VERY large long to an int
- new_offset = _document_size;
- }
- else if (new_offset > _document_size)
- {
- new_offset = _document_size;
- }
- long rval = new_offset - _current_offset;
-
- _current_offset = new_offset;
- return rval;
- }
-
- private void dieIfClosed()
- throws IOException
- {
- if (_closed)
- {
- throw new IOException(
- "cannot perform requested operation on a closed stream");
- }
- }
-
- private boolean atEOD()
- {
- return _current_offset == _document_size;
- }
-} // end public class DocumentInputStream
-
+public final class DocumentInputStream extends InputStream implements LittleEndianInput {
+ /** returned by read operations if we're at end of document */
+ private static final int EOF = -1;
+
+ private static final int SIZE_SHORT = 2;
+ private static final int SIZE_INT = 4;
+ private static final int SIZE_LONG = 8;
+
+ /** current offset into the Document */
+ private int _current_offset;
+
+ /** current marked offset into the Document (used by mark and reset) */
+ private int _marked_offset;
+
+ /** the Document's size */
+ private int _document_size;
+
+ /** have we been closed? */
+ private boolean _closed;
+
+ /** the actual Document */
+ private POIFSDocument _document;
+
+ /** the data block containing the current stream pointer */
+ private DataInputBlock _currentBlock;
+
+ /**
+ * Create an InputStream from the specified DocumentEntry
+ *
+ * @param document the DocumentEntry to be read
+ *
+ * @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
+ * been deleted?)
+ */
+ public DocumentInputStream(DocumentEntry document) throws IOException {
+ if (!(document instanceof DocumentNode)) {
+ throw new IOException("Cannot open internal document storage");
+ }
+ _current_offset = 0;
+ _marked_offset = 0;
+ _document_size = document.getSize();
+ _closed = false;
+ _document = ((DocumentNode) document).getDocument();
+ _currentBlock = getDataInputBlock(0);
+ }
+
+ /**
+ * Create an InputStream from the specified Document
+ *
+ * @param document the Document to be read
+ */
+ public DocumentInputStream(POIFSDocument document) {
+ _current_offset = 0;
+ _marked_offset = 0;
+ _document_size = document.getSize();
+ _closed = false;
+ _document = document;
+ _currentBlock = getDataInputBlock(0);
+ }
+
+ public int available() {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
+ return _document_size - _current_offset;
+ }
+
+ public void close() {
+ _closed = true;
+ }
+
+ public void mark(int ignoredReadlimit) {
+ _marked_offset = _current_offset;
+ }
+
+ /**
+ * Tests if this input stream supports the mark and reset methods.
+ *
+ * @return <code>true</code> always
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ private DataInputBlock getDataInputBlock(int offset) {
+ return _document.getDataInputBlock(offset);
+ }
+
+ public int read() throws IOException {
+ dieIfClosed();
+ if (atEOD()) {
+ return EOF;
+ }
+ int result = _currentBlock.readUByte();
+ _current_offset++;
+ if (_currentBlock.available() < 1) {
+ _currentBlock = getDataInputBlock(_current_offset);
+ }
+ return result;
+ }
+
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ dieIfClosed();
+ if (b == null) {
+ throw new IllegalArgumentException("buffer must not be null");
+ }
+ if (off < 0 || len < 0 || b.length < off + len) {
+ throw new IndexOutOfBoundsException("can't read past buffer boundaries");
+ }
+ if (len == 0) {
+ return 0;
+ }
+ if (atEOD()) {
+ return EOF;
+ }
+ int limit = Math.min(available(), len);
+ readFully(b, off, limit);
+ return limit;
+ }
+
+ /**
+ * Repositions this stream to the position at the time the mark() method was
+ * last called on this input stream. If mark() has not been called this
+ * method repositions the stream to its beginning.
+ */
+ public void reset() {
+ _current_offset = _marked_offset;
+ _currentBlock = getDataInputBlock(_current_offset);
+ }
+
+ public long skip(long n) throws IOException {
+ dieIfClosed();
+ if (n < 0) {
+ return 0;
+ }
+ int new_offset = _current_offset + (int) n;
+
+ if (new_offset < _current_offset) {
+
+ // wrap around in converting a VERY large long to an int
+ new_offset = _document_size;
+ } else if (new_offset > _document_size) {
+ new_offset = _document_size;
+ }
+ long rval = new_offset - _current_offset;
+
+ _current_offset = new_offset;
+ _currentBlock = getDataInputBlock(_current_offset);
+ return rval;
+ }
+
+ private void dieIfClosed() throws IOException {
+ if (_closed) {
+ throw new IOException("cannot perform requested operation on a closed stream");
+ }
+ }
+
+ private boolean atEOD() {
+ return _current_offset == _document_size;
+ }
+
+ private void checkAvaliable(int requestedSize) {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
+ if (requestedSize > _document_size - _current_offset) {
+ throw new RuntimeException("Buffer underrun - requested " + requestedSize
+ + " bytes but " + (_document_size - _current_offset) + " was available");
+ }
+ }
+
+ public byte readByte() {
+ return (byte) readUByte();
+ }
+
+ public double readDouble() {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ public void readFully(byte[] buf) {
+ readFully(buf, 0, buf.length);
+ }
+
+ public short readShort() {
+ return (short) readUShort();
+ }
+
+ public void readFully(byte[] buf, int off, int len) {
+ checkAvaliable(len);
+ int blockAvailable = _currentBlock.available();
+ if (blockAvailable > len) {
+ _currentBlock.readFully(buf, off, len);
+ _current_offset += len;
+ return;
+ }
+ // else read big amount in chunks
+ int remaining = len;
+ int writePos = off;
+ while (remaining > 0) {
+ boolean blockIsExpiring = remaining >= blockAvailable;
+ int reqSize;
+ if (blockIsExpiring) {
+ reqSize = blockAvailable;
+ } else {
+ reqSize = remaining;
+ }
+ _currentBlock.readFully(buf, writePos, reqSize);
+ remaining -= reqSize;
+ writePos += reqSize;
+ _current_offset += reqSize;
+ if (blockIsExpiring) {
+ if (_current_offset == _document_size) {
+ if (remaining > 0) {
+ throw new IllegalStateException(
+ "reached end of document stream unexpectedly");
+ }
+ _currentBlock = null;
+ break;
+ }
+ _currentBlock = getDataInputBlock(_current_offset);
+ blockAvailable = _currentBlock.available();
+ }
+ }
+ }
+
+ public long readLong() {
+ checkAvaliable(SIZE_LONG);
+ int blockAvailable = _currentBlock.available();
+ long result;
+ if (blockAvailable > SIZE_LONG) {
+ result = _currentBlock.readLongLE();
+ } else {
+ DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+ if (blockAvailable == SIZE_LONG) {
+ result = _currentBlock.readLongLE();
+ } else {
+ result = nextBlock.readLongLE(_currentBlock, blockAvailable);
+ }
+ _currentBlock = nextBlock;
+ }
+ _current_offset += SIZE_LONG;
+ return result;
+ }
+
+ public int readInt() {
+ checkAvaliable(SIZE_INT);
+ int blockAvailable = _currentBlock.available();
+ int result;
+ if (blockAvailable > SIZE_INT) {
+ result = _currentBlock.readIntLE();
+ } else {
+ DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+ if (blockAvailable == SIZE_INT) {
+ result = _currentBlock.readIntLE();
+ } else {
+ result = nextBlock.readIntLE(_currentBlock, blockAvailable);
+ }
+ _currentBlock = nextBlock;
+ }
+ _current_offset += SIZE_INT;
+ return result;
+ }
+
+ public int readUShort() {
+ checkAvaliable(SIZE_SHORT);
+ int blockAvailable = _currentBlock.available();
+ int result;
+ if (blockAvailable > SIZE_SHORT) {
+ result = _currentBlock.readUShortLE();
+ } else {
+ DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+ if (blockAvailable == SIZE_SHORT) {
+ result = _currentBlock.readUShortLE();
+ } else {
+ result = nextBlock.readUShortLE(_currentBlock);
+ }
+ _currentBlock = nextBlock;
+ }
+ _current_offset += SIZE_SHORT;
+ return result;
+ }
+
+ public int readUByte() {
+ checkAvaliable(1);
+ int result = _currentBlock.readUByte();
+ _current_offset++;
+ if (_currentBlock.available() < 1) {
+ _currentBlock = getDataInputBlock(_current_offset);
+ }
+ return result;
+ }
+}
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.filesystem;
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.storage.BlockWritable;
-import org.apache.poi.poifs.storage.ListManagedBlock;
+import org.apache.poi.poifs.storage.DataInputBlock;
import org.apache.poi.poifs.storage.DocumentBlock;
+import org.apache.poi.poifs.storage.ListManagedBlock;
import org.apache.poi.poifs.storage.RawDataBlock;
import org.apache.poi.poifs.storage.SmallDocumentBlock;
import org.apache.poi.util.HexDump;
*
* @author Marc Johnson (mjohnson at apache dot org)
*/
-
-public class POIFSDocument
- implements BATManaged, BlockWritable, POIFSViewable
-{
- private DocumentProperty _property;
- private int _size;
-
- // one of these stores will be valid
- private SmallBlockStore _small_store;
- private BigBlockStore _big_store;
-
- /**
- * Constructor from large blocks
- *
- * @param name the name of the POIFSDocument
- * @param blocks the big blocks making up the POIFSDocument
- * @param length the actual length of the POIFSDocument
- *
- * @exception IOException
- */
-
- public POIFSDocument(final String name, final RawDataBlock [] blocks,
- final int length)
- throws IOException
- {
- _size = length;
- _big_store = new BigBlockStore(blocks);
- _property = new DocumentProperty(name, _size);
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- _property.setDocument(this);
- }
-
- /**
- * Constructor from small blocks
- *
- * @param name the name of the POIFSDocument
- * @param blocks the small blocks making up the POIFSDocument
- * @param length the actual length of the POIFSDocument
- */
-
- public POIFSDocument(final String name,
- final SmallDocumentBlock [] blocks, final int length)
- {
- _size = length;
- try
- {
- _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
- }
- catch (IOException ignored)
- {
-
- // can't happen with that constructor
- }
- _property = new DocumentProperty(name, _size);
- _small_store = new SmallBlockStore(blocks);
- _property.setDocument(this);
- }
-
- /**
- * Constructor from small blocks
- *
- * @param name the name of the POIFSDocument
- * @param blocks the small blocks making up the POIFSDocument
- * @param length the actual length of the POIFSDocument
- *
- * @exception IOException
- */
-
- public POIFSDocument(final String name, final ListManagedBlock [] blocks,
- final int length)
- throws IOException
- {
- _size = length;
- _property = new DocumentProperty(name, _size);
- _property.setDocument(this);
- if (Property.isSmall(_size))
- {
- _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
- _small_store = new SmallBlockStore(blocks);
- }
- else
- {
- _big_store = new BigBlockStore(blocks);
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- }
- }
-
- /**
- * Constructor
- *
- * @param name the name of the POIFSDocument
- * @param stream the InputStream we read data from
- *
- * @exception IOException thrown on read errors
- */
-
- public POIFSDocument(final String name, final InputStream stream)
- throws IOException
- {
- List blocks = new ArrayList();
-
- _size = 0;
- while (true)
- {
- DocumentBlock block = new DocumentBlock(stream);
- int blockSize = block.size();
-
- if (blockSize > 0)
- {
- blocks.add(block);
- _size += blockSize;
- }
- if (block.partiallyRead())
- {
- break;
- }
- }
- DocumentBlock[] bigBlocks =
- ( DocumentBlock [] ) blocks.toArray(new DocumentBlock[ 0 ]);
-
- _big_store = new BigBlockStore(bigBlocks);
- _property = new DocumentProperty(name, _size);
- _property.setDocument(this);
- if (_property.shouldUseSmallBlocks())
- {
- _small_store =
- new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks,
- _size));
- _big_store = new BigBlockStore(new DocumentBlock[ 0 ]);
- }
- else
- {
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- }
- }
-
- /**
- * Constructor
- *
- * @param name the name of the POIFSDocument
- * @param size the length of the POIFSDocument
- * @param path the path of the POIFSDocument
- * @param writer the writer who will eventually write the document
- * contents
- *
- * @exception IOException thrown on read errors
- */
-
- public POIFSDocument(final String name, final int size,
- final POIFSDocumentPath path,
- final POIFSWriterListener writer)
- throws IOException
- {
- _size = size;
- _property = new DocumentProperty(name, _size);
- _property.setDocument(this);
- if (_property.shouldUseSmallBlocks())
- {
- _small_store = new SmallBlockStore(path, name, size, writer);
- _big_store = new BigBlockStore(new Object[ 0 ]);
- }
- else
- {
- _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
- _big_store = new BigBlockStore(path, name, size, writer);
- }
- }
-
- /**
- * return the array of SmallDocumentBlocks used
- *
- * @return array of SmallDocumentBlocks; may be empty, cannot be null
- */
-
- public BlockWritable [] getSmallBlocks()
- {
- return _small_store.getBlocks();
- }
-
- /**
- * @return size of the document
- */
-
- public int getSize()
- {
- return _size;
- }
-
- /**
- * read data from the internal stores
- *
- * @param buffer the buffer to write to
- * @param offset the offset into our storage to read from
- */
-
- void read(final byte [] buffer, final int offset)
- {
- if (_property.shouldUseSmallBlocks())
- {
- SmallDocumentBlock.read(_small_store.getBlocks(), buffer, offset);
- }
- else
- {
- DocumentBlock.read(_big_store.getBlocks(), buffer, offset);
- }
- }
-
- /**
- * Get the DocumentProperty
- *
- * @return the instance's DocumentProperty
- */
-
- DocumentProperty getDocumentProperty()
- {
- return _property;
- }
-
- /* ********** START implementation of BlockWritable ********** */
-
- /**
- * Write the storage to an OutputStream
- *
- * @param stream the OutputStream to which the stored data should
- * be written
- *
- * @exception IOException on problems writing to the specified
- * stream
- */
-
- public void writeBlocks(final OutputStream stream)
- throws IOException
- {
- _big_store.writeBlocks(stream);
- }
-
- /* ********** END implementation of BlockWritable ********** */
- /* ********** START implementation of BATManaged ********** */
-
- /**
- * Return the number of BigBlock's this instance uses
- *
- * @return count of BigBlock instances
- */
-
- public int countBlocks()
- {
- return _big_store.countBlocks();
- }
-
- /**
- * Set the start block for this instance
- *
- * @param index index into the array of blocks making up the
- * filesystem
- */
-
- public void setStartBlock(final int index)
- {
- _property.setStartBlock(index);
- }
-
- /* ********** END implementation of BATManaged ********** */
- /* ********** START begin implementation of POIFSViewable ********** */
-
- /**
- * Get an array of objects, some of which may implement
- * POIFSViewable
- *
- * @return an array of Object; may not be null, but may be empty
- */
-
- public Object [] getViewableArray()
- {
- Object[] results = new Object[ 1 ];
- String result;
-
- try
- {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- BlockWritable[] blocks = null;
-
- if (_big_store.isValid())
- {
- blocks = _big_store.getBlocks();
- }
- else if (_small_store.isValid())
- {
- blocks = _small_store.getBlocks();
- }
- if (blocks != null)
- {
- for (int k = 0; k < blocks.length; k++)
- {
- blocks[ k ].writeBlocks(output);
- }
- byte[] data = output.toByteArray();
-
- if (data.length > _property.getSize())
- {
- byte[] tmp = new byte[ _property.getSize() ];
-
- System.arraycopy(data, 0, tmp, 0, tmp.length);
- data = tmp;
- }
- output = new ByteArrayOutputStream();
- HexDump.dump(data, 0, output, 0);
- result = output.toString();
- }
- else
- {
- result = "<NO DATA>";
- }
- }
- catch (IOException e)
- {
- result = e.getMessage();
- }
- results[ 0 ] = result;
- return results;
- }
-
- /**
- * Get an Iterator of objects, some of which may implement
- * POIFSViewable
- *
- * @return an Iterator; may not be null, but may have an empty
- * back end store
- */
-
- public Iterator getViewableIterator()
- {
- return Collections.EMPTY_LIST.iterator();
- }
-
- /**
- * Give viewers a hint as to whether to call getViewableArray or
- * getViewableIterator
- *
- * @return true if a viewer should call getViewableArray, false if
- * a viewer should call getViewableIterator
- */
-
- public boolean preferArray()
- {
- return true;
- }
-
- /**
- * Provides a short description of the object, to be used when a
- * POIFSViewable object has not provided its contents.
- *
- * @return short description
- */
-
- public String getShortDescription()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append("Document: \"").append(_property.getName())
- .append("\"");
- buffer.append(" size = ").append(getSize());
- return buffer.toString();
- }
-
- /* ********** END begin implementation of POIFSViewable ********** */
- private class SmallBlockStore
- {
- private SmallDocumentBlock[] smallBlocks;
- private POIFSDocumentPath path;
- private String name;
- private int size;
- private POIFSWriterListener writer;
-
- /**
- * Constructor
- *
- * @param blocks blocks to construct the store from
- */
-
- SmallBlockStore(final Object [] blocks)
- {
- smallBlocks = new SmallDocumentBlock[ blocks.length ];
- for (int j = 0; j < blocks.length; j++)
- {
- smallBlocks[ j ] = ( SmallDocumentBlock ) blocks[ j ];
- }
- this.path = null;
- this.name = null;
- this.size = -1;
- this.writer = null;
- }
-
- /**
- * Constructor for a small block store that will be written
- * later
- *
- * @param path path of the document
- * @param name name of the document
- * @param size length of the document
- * @param writer the object that will eventually write the document
- */
-
- SmallBlockStore(final POIFSDocumentPath path, final String name,
- final int size, final POIFSWriterListener writer)
- {
- smallBlocks = new SmallDocumentBlock[ 0 ];
- this.path = path;
- this.name = name;
- this.size = size;
- this.writer = writer;
- }
-
- /**
- * @return true if this store is a valid source of data
- */
-
- boolean isValid()
- {
- return ((smallBlocks.length > 0) || (writer != null));
- }
-
- /**
- * @return the SmallDocumentBlocks
- */
-
- BlockWritable [] getBlocks()
- {
- if (isValid() && (writer != null))
- {
- ByteArrayOutputStream stream =
- new ByteArrayOutputStream(size);
- DocumentOutputStream dstream =
- new DocumentOutputStream(stream, size);
-
- writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
- path, name, size));
- smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(),
- size);
- }
- return smallBlocks;
- }
- } // end private class SmallBlockStore
-
- private class BigBlockStore
- {
- private DocumentBlock[] bigBlocks;
- private POIFSDocumentPath path;
- private String name;
- private int size;
- private POIFSWriterListener writer;
-
- /**
- * Constructor
- *
- * @param blocks the blocks making up the store
- *
- * @exception IOException on I/O error
- */
-
- BigBlockStore(final Object [] blocks)
- throws IOException
- {
- bigBlocks = new DocumentBlock[ blocks.length ];
- for (int j = 0; j < blocks.length; j++)
- {
- if (blocks[ j ] instanceof DocumentBlock)
- {
- bigBlocks[ j ] = ( DocumentBlock ) blocks[ j ];
- }
- else
- {
- bigBlocks[ j ] =
- new DocumentBlock(( RawDataBlock ) blocks[ j ]);
- }
- }
- this.path = null;
- this.name = null;
- this.size = -1;
- this.writer = null;
- }
-
- /**
- * Constructor for a big block store that will be written
- * later
- *
- * @param path path of the document
- * @param name name of the document
- * @param size length of the document
- * @param writer the object that will eventually write the
- * document
- */
-
- BigBlockStore(final POIFSDocumentPath path, final String name,
- final int size, final POIFSWriterListener writer)
- {
- bigBlocks = new DocumentBlock[ 0 ];
- this.path = path;
- this.name = name;
- this.size = size;
- this.writer = writer;
- }
-
- /**
- * @return true if this store is a valid source of data
- */
-
- boolean isValid()
- {
- return ((bigBlocks.length > 0) || (writer != null));
- }
-
- /**
- * @return the DocumentBlocks
- */
-
- DocumentBlock [] getBlocks()
- {
- if (isValid() && (writer != null))
- {
- ByteArrayOutputStream stream =
- new ByteArrayOutputStream(size);
- DocumentOutputStream dstream =
- new DocumentOutputStream(stream, size);
-
- writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
- path, name, size));
- bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
- }
- return bigBlocks;
- }
-
- /**
- * write the blocks to a stream
- *
- * @param stream the stream to which the data is to be written
- *
- * @exception IOException on error
- */
-
- void writeBlocks(OutputStream stream)
- throws IOException
- {
- if (isValid())
- {
- if (writer != null)
- {
- DocumentOutputStream dstream =
- new DocumentOutputStream(stream, size);
-
- writer.processPOIFSWriterEvent(
- new POIFSWriterEvent(dstream, path, name, size));
- dstream.writeFiller(countBlocks()
- * POIFSConstants
- .BIG_BLOCK_SIZE, DocumentBlock
- .getFillByte());
- }
- else
- {
- for (int k = 0; k < bigBlocks.length; k++)
- {
- bigBlocks[ k ].writeBlocks(stream);
- }
- }
- }
- }
-
- /**
- * @return number of big blocks making up this document
- */
-
- int countBlocks()
- {
- int rval = 0;
-
- if (isValid())
- {
- if (writer != null)
- {
- rval = (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
- / POIFSConstants.BIG_BLOCK_SIZE;
- }
- else
- {
- rval = bigBlocks.length;
- }
- }
- return rval;
- }
- } // end private class BigBlockStore
-} // end class POIFSDocument
-
+public final class POIFSDocument implements BATManaged, BlockWritable, POIFSViewable {
+ private static final DocumentBlock[] EMPTY_BIG_BLOCK_ARRAY = { };
+ private static final SmallDocumentBlock[] EMPTY_SMALL_BLOCK_ARRAY = { };
+ private DocumentProperty _property;
+ private int _size;
+
+ // one of these stores will be valid
+ private SmallBlockStore _small_store;
+ private BigBlockStore _big_store;
+
+ /**
+ * Constructor from large blocks
+ *
+ * @param name the name of the POIFSDocument
+ * @param blocks the big blocks making up the POIFSDocument
+ * @param length the actual length of the POIFSDocument
+ */
+ public POIFSDocument(String name, RawDataBlock[] blocks, int length) throws IOException {
+ _size = length;
+ _big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
+ _property = new DocumentProperty(name, _size);
+ _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+ _property.setDocument(this);
+ }
+
+ // TODO - awkward typing going on here
+ private static DocumentBlock[] convertRawBlocksToBigBlocks(ListManagedBlock[] blocks) throws IOException {
+ DocumentBlock[] result = new DocumentBlock[blocks.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = new DocumentBlock((RawDataBlock)blocks[i]);
+ }
+ return result;
+ }
+ private static SmallDocumentBlock[] convertRawBlocksToSmallBlocks(ListManagedBlock[] blocks) {
+ if (blocks instanceof SmallDocumentBlock[]) {
+ return (SmallDocumentBlock[]) blocks;
+ }
+ SmallDocumentBlock[] result = new SmallDocumentBlock[blocks.length];
+ System.arraycopy(blocks, 0, result, 0, blocks.length);
+ return result;
+ }
+
+ /**
+ * Constructor from small blocks
+ *
+ * @param name the name of the POIFSDocument
+ * @param blocks the small blocks making up the POIFSDocument
+ * @param length the actual length of the POIFSDocument
+ */
+ public POIFSDocument(String name, SmallDocumentBlock[] blocks, int length) {
+ _size = length;
+ _big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+ _property = new DocumentProperty(name, _size);
+ _small_store = new SmallBlockStore(blocks);
+ _property.setDocument(this);
+ }
+
+ /**
+ * Constructor from small blocks
+ *
+ * @param name the name of the POIFSDocument
+ * @param blocks the small blocks making up the POIFSDocument
+ * @param length the actual length of the POIFSDocument
+ */
+ public POIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
+ _size = length;
+ _property = new DocumentProperty(name, _size);
+ _property.setDocument(this);
+ if (Property.isSmall(_size)) {
+ _big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+ _small_store = new SmallBlockStore(convertRawBlocksToSmallBlocks(blocks));
+ } else {
+ _big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
+ _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param name the name of the POIFSDocument
+ * @param stream the InputStream we read data from
+ */
+ public POIFSDocument(String name, InputStream stream) throws IOException {
+ List blocks = new ArrayList();
+
+ _size = 0;
+ while (true) {
+ DocumentBlock block = new DocumentBlock(stream);
+ int blockSize = block.size();
+
+ if (blockSize > 0) {
+ blocks.add(block);
+ _size += blockSize;
+ }
+ if (block.partiallyRead()) {
+ break;
+ }
+ }
+ DocumentBlock[] bigBlocks = (DocumentBlock[]) blocks.toArray(new DocumentBlock[blocks.size()]);
+
+ _big_store = new BigBlockStore(bigBlocks);
+ _property = new DocumentProperty(name, _size);
+ _property.setDocument(this);
+ if (_property.shouldUseSmallBlocks()) {
+ _small_store = new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks, _size));
+ _big_store = new BigBlockStore(new DocumentBlock[0]);
+ } else {
+ _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param name the name of the POIFSDocument
+ * @param size the length of the POIFSDocument
+ * @param path the path of the POIFSDocument
+ * @param writer the writer who will eventually write the document contents
+ */
+ public POIFSDocument(String name, int size, POIFSDocumentPath path, POIFSWriterListener writer) {
+ _size = size;
+ _property = new DocumentProperty(name, _size);
+ _property.setDocument(this);
+ if (_property.shouldUseSmallBlocks()) {
+ _small_store = new SmallBlockStore(path, name, size, writer);
+ _big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+ } else {
+ _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+ _big_store = new BigBlockStore(path, name, size, writer);
+ }
+ }
+
+ /**
+ * @return array of SmallDocumentBlocks; may be empty, cannot be null
+ */
+ public BlockWritable[] getSmallBlocks() {
+ return _small_store.getBlocks();
+ }
+
+ /**
+ * @return size of the document
+ */
+ public int getSize() {
+ return _size;
+ }
+
+ /**
+ * read data from the internal stores
+ *
+ * @param buffer the buffer to write to
+ * @param offset the offset into our storage to read from
+ * This method is currently (Oct 2008) only used by test code. Perhaps it can be deleted
+ */
+ void read(byte[] buffer, int offset) {
+ int len = buffer.length;
+
+ DataInputBlock currentBlock = getDataInputBlock(offset);
+
+ int blockAvailable = currentBlock.available();
+ if (blockAvailable > len) {
+ currentBlock.readFully(buffer, 0, len);
+ return;
+ }
+ // else read big amount in chunks
+ int remaining = len;
+ int writePos = 0;
+ int currentOffset = offset;
+ while (remaining > 0) {
+ boolean blockIsExpiring = remaining >= blockAvailable;
+ int reqSize;
+ if (blockIsExpiring) {
+ reqSize = blockAvailable;
+ } else {
+ reqSize = remaining;
+ }
+ currentBlock.readFully(buffer, writePos, reqSize);
+ remaining-=reqSize;
+ writePos+=reqSize;
+ currentOffset += reqSize;
+ if (blockIsExpiring) {
+ if (currentOffset == _size) {
+ if (remaining > 0) {
+ throw new IllegalStateException("reached end of document stream unexpectedly");
+ }
+ currentBlock = null;
+ break;
+ }
+ currentBlock = getDataInputBlock(currentOffset);
+ blockAvailable = currentBlock.available();
+ }
+ }
+ }
+
+ /**
+ * @return <code>null</code> if <tt>offset</tt> points to the end of the document stream
+ */
+ DataInputBlock getDataInputBlock(int offset) {
+ if (offset >= _size) {
+ if (offset > _size) {
+ throw new RuntimeException("Request for Offset " + offset + " doc size is " + _size);
+ }
+ return null;
+ }
+ if (_property.shouldUseSmallBlocks()) {
+ return SmallDocumentBlock.getDataInputBlock(_small_store.getBlocks(), offset);
+ } else {
+ return DocumentBlock.getDataInputBlock(_big_store.getBlocks(), offset);
+ }
+ }
+
+ /**
+ * @return the instance's DocumentProperty
+ */
+
+ DocumentProperty getDocumentProperty() {
+ return _property;
+ }
+
+ /* ********** START implementation of BlockWritable ********** */
+
+ /**
+ * Write the storage to an OutputStream
+ *
+ * @param stream the OutputStream to which the stored data should be written
+ */
+ public void writeBlocks(OutputStream stream) throws IOException {
+ _big_store.writeBlocks(stream);
+ }
+
+ /* ********** END implementation of BlockWritable ********** */
+ /* ********** START implementation of BATManaged ********** */
+
+ /**
+ * Return the number of BigBlock's this instance uses
+ *
+ * @return count of BigBlock instances
+ */
+ public int countBlocks() {
+ return _big_store.countBlocks();
+ }
+
+ /**
+ * Set the start block for this instance
+ *
+ * @param index index into the array of blocks making up the filesystem
+ */
+ public void setStartBlock(int index) {
+ _property.setStartBlock(index);
+ }
+
+ /* ********** END implementation of BATManaged ********** */
+ /* ********** START begin implementation of POIFSViewable ********** */
+
+ /**
+ * Get an array of objects, some of which may implement POIFSViewable
+ *
+ * @return an array of Object; may not be null, but may be empty
+ */
+ public Object[] getViewableArray() {
+ Object[] results = new Object[1];
+ String result;
+
+ try {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ BlockWritable[] blocks = null;
+
+ if (_big_store.isValid()) {
+ blocks = _big_store.getBlocks();
+ } else if (_small_store.isValid()) {
+ blocks = _small_store.getBlocks();
+ }
+ if (blocks != null) {
+ for (int k = 0; k < blocks.length; k++) {
+ blocks[k].writeBlocks(output);
+ }
+ byte[] data = output.toByteArray();
+
+ if (data.length > _property.getSize()) {
+ byte[] tmp = new byte[_property.getSize()];
+
+ System.arraycopy(data, 0, tmp, 0, tmp.length);
+ data = tmp;
+ }
+ output = new ByteArrayOutputStream();
+ HexDump.dump(data, 0, output, 0);
+ result = output.toString();
+ } else {
+ result = "<NO DATA>";
+ }
+ } catch (IOException e) {
+ result = e.getMessage();
+ }
+ results[0] = result;
+ return results;
+ }
+
+ /**
+ * Get an Iterator of objects, some of which may implement POIFSViewable
+ *
+ * @return an Iterator; may not be null, but may have an empty back end
+ * store
+ */
+ public Iterator getViewableIterator() {
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ /**
+ * Give viewers a hint as to whether to call getViewableArray or
+ * getViewableIterator
+ *
+ * @return <code>true</code> if a viewer should call getViewableArray,
+ * <code>false</code> if a viewer should call getViewableIterator
+ */
+ public boolean preferArray() {
+ return true;
+ }
+
+ /**
+ * Provides a short description of the object, to be used when a
+ * POIFSViewable object has not provided its contents.
+ *
+ * @return short description
+ */
+ public String getShortDescription() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("Document: \"").append(_property.getName()).append("\"");
+ buffer.append(" size = ").append(getSize());
+ return buffer.toString();
+ }
+
+ /* ********** END begin implementation of POIFSViewable ********** */
+ private static final class SmallBlockStore {
+ private SmallDocumentBlock[] smallBlocks;
+ private final POIFSDocumentPath path;
+ private final String name;
+ private final int size;
+ private final POIFSWriterListener writer;
+
+ /**
+ * Constructor
+ *
+ * @param blocks blocks to construct the store from
+ */
+ SmallBlockStore(SmallDocumentBlock[] blocks) {
+ smallBlocks = (SmallDocumentBlock[]) blocks.clone();
+ this.path = null;
+ this.name = null;
+ this.size = -1;
+ this.writer = null;
+ }
+
+ /**
+ * Constructor for a small block store that will be written later
+ *
+ * @param path path of the document
+ * @param name name of the document
+ * @param size length of the document
+ * @param writer the object that will eventually write the document
+ */
+ SmallBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
+ smallBlocks = new SmallDocumentBlock[0];
+ this.path = path;
+ this.name = name;
+ this.size = size;
+ this.writer = writer;
+ }
+
+ /**
+ * @return <code>true</code> if this store is a valid source of data
+ */
+ boolean isValid() {
+ return smallBlocks.length > 0 || writer != null;
+ }
+
+ /**
+ * @return the SmallDocumentBlocks
+ */
+ SmallDocumentBlock[] getBlocks() {
+ if (isValid() && writer != null) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
+ DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
+
+ writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
+ smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(), size);
+ }
+ return smallBlocks;
+ }
+ } // end private class SmallBlockStore
+
+ private static final class BigBlockStore {
+ private DocumentBlock[] bigBlocks;
+ private final POIFSDocumentPath path;
+ private final String name;
+ private final int size;
+ private final POIFSWriterListener writer;
+
+ /**
+ * Constructor
+ *
+ * @param blocks the blocks making up the store
+ */
+ BigBlockStore(DocumentBlock[] blocks) {
+ bigBlocks = (DocumentBlock[]) blocks.clone();
+ this.path = null;
+ this.name = null;
+ this.size = -1;
+ this.writer = null;
+ }
+
+ /**
+ * Constructor for a big block store that will be written later
+ *
+ * @param path path of the document
+ * @param name name of the document
+ * @param size length of the document
+ * @param writer the object that will eventually write the document
+ */
+ BigBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
+ bigBlocks = new DocumentBlock[0];
+ this.path = path;
+ this.name = name;
+ this.size = size;
+ this.writer = writer;
+ }
+
+ /**
+ * @return <code>true</code> if this store is a valid source of data
+ */
+ boolean isValid() {
+ return bigBlocks.length > 0 || writer != null;
+ }
+
+ /**
+ * @return the DocumentBlocks
+ */
+ DocumentBlock[] getBlocks() {
+ if (isValid() && writer != null) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
+ DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
+
+ writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
+ bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
+ }
+ return bigBlocks;
+ }
+
+ /**
+ * write the blocks to a stream
+ *
+ * @param stream the stream to which the data is to be written
+ */
+ void writeBlocks(OutputStream stream) throws IOException {
+ if (isValid()) {
+ if (writer != null) {
+ DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
+
+ writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
+ dstream.writeFiller(countBlocks() * POIFSConstants.BIG_BLOCK_SIZE,
+ DocumentBlock.getFillByte());
+ } else {
+ for (int k = 0; k < bigBlocks.length; k++) {
+ bigBlocks[k].writeBlocks(stream);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return number of big blocks making up this document
+ */
+ int countBlocks() {
+
+ if (isValid()) {
+ if (writer == null) {
+ return bigBlocks.length;
+ }
+ return (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
+ / POIFSConstants.BIG_BLOCK_SIZE;
+ }
+ return 0;
+ }
+ } // end private class BigBlockStore
+}
--- /dev/null
+/* ====================================================================
+ 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.poifs.storage;
+
+/**
+ * Wraps a <tt>byte</tt> array and provides simple data input access.
+ * Internally, this class maintains a buffer read index, so that for the most part, primitive
+ * data can be read in a data-input-stream-like manner.<p/>
+ *
+ * Note - the calling class should call the {@link #available()} method to detect end-of-buffer
+ * and move to the next data block when the current is exhausted.
+ * For optimisation reasons, no error handling is performed in this class. Thus, mistakes in
+ * calling code ran may raise ugly exceptions here, like {@link ArrayIndexOutOfBoundsException},
+ * etc .<p/>
+ *
+ * The multi-byte primitive input methods ({@link #readUShortLE()}, {@link #readIntLE()} and
+ * {@link #readLongLE()}) have corresponding 'spanning read' methods which (when required) perform
+ * a read across the block boundary. These spanning read methods take the previous
+ * {@link DataInputBlock} as a parameter.
+ * Reads of larger amounts of data (into <tt>byte</tt> array buffers) must be managed by the caller
+ * since these could conceivably involve more than two blocks.
+ *
+ * @author Josh Micich
+ */
+public final class DataInputBlock {
+
+ /**
+ * Possibly any size (usually 512K or 64K). Assumed to be at least 8 bytes for all blocks
+ * before the end of the stream. The last block in the stream can be any size except zero.
+ */
+ private final byte[] _buf;
+ private int _readIndex;
+ private int _maxIndex;
+
+ DataInputBlock(byte[] data, int startOffset) {
+ _buf = data;
+ _readIndex = startOffset;
+ _maxIndex = _buf.length;
+ }
+ public int available() {
+ return _maxIndex-_readIndex;
+ }
+
+ public int readUByte() {
+ return _buf[_readIndex++] & 0xFF;
+ }
+
+ /**
+ * Reads a <tt>short</tt> which was encoded in <em>little endian</em> format.
+ */
+ public int readUShortLE() {
+ int i = _readIndex;
+
+ int b0 = _buf[i++] & 0xFF;
+ int b1 = _buf[i++] & 0xFF;
+ _readIndex = i;
+ return (b1 << 8) + (b0 << 0);
+ }
+
+ /**
+ * Reads a <tt>short</tt> which spans the end of <tt>prevBlock</tt> and the start of this block.
+ */
+ public int readUShortLE(DataInputBlock prevBlock) {
+ // simple case - will always be one byte in each block
+ int i = prevBlock._buf.length-1;
+
+ int b0 = prevBlock._buf[i++] & 0xFF;
+ int b1 = _buf[_readIndex++] & 0xFF;
+ return (b1 << 8) + (b0 << 0);
+ }
+
+ /**
+ * Reads an <tt>int</tt> which was encoded in <em>little endian</em> format.
+ */
+ public int readIntLE() {
+ int i = _readIndex;
+
+ int b0 = _buf[i++] & 0xFF;
+ int b1 = _buf[i++] & 0xFF;
+ int b2 = _buf[i++] & 0xFF;
+ int b3 = _buf[i++] & 0xFF;
+ _readIndex = i;
+ return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
+ }
+
+ /**
+ * Reads an <tt>int</tt> which spans the end of <tt>prevBlock</tt> and the start of this block.
+ */
+ public int readIntLE(DataInputBlock prevBlock, int prevBlockAvailable) {
+ byte[] buf = new byte[4];
+
+ readSpanning(prevBlock, prevBlockAvailable, buf);
+ int b0 = buf[0] & 0xFF;
+ int b1 = buf[1] & 0xFF;
+ int b2 = buf[2] & 0xFF;
+ int b3 = buf[3] & 0xFF;
+ return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
+ }
+
+ /**
+ * Reads a <tt>long</tt> which was encoded in <em>little endian</em> format.
+ */
+ public long readLongLE() {
+ int i = _readIndex;
+
+ int b0 = _buf[i++] & 0xFF;
+ int b1 = _buf[i++] & 0xFF;
+ int b2 = _buf[i++] & 0xFF;
+ int b3 = _buf[i++] & 0xFF;
+ int b4 = _buf[i++] & 0xFF;
+ int b5 = _buf[i++] & 0xFF;
+ int b6 = _buf[i++] & 0xFF;
+ int b7 = _buf[i++] & 0xFF;
+ _readIndex = i;
+ return (((long)b7 << 56) +
+ ((long)b6 << 48) +
+ ((long)b5 << 40) +
+ ((long)b4 << 32) +
+ ((long)b3 << 24) +
+ (b2 << 16) +
+ (b1 << 8) +
+ (b0 << 0));
+ }
+
+ /**
+ * Reads a <tt>long</tt> which spans the end of <tt>prevBlock</tt> and the start of this block.
+ */
+ public long readLongLE(DataInputBlock prevBlock, int prevBlockAvailable) {
+ byte[] buf = new byte[8];
+
+ readSpanning(prevBlock, prevBlockAvailable, buf);
+
+ int b0 = buf[0] & 0xFF;
+ int b1 = buf[1] & 0xFF;
+ int b2 = buf[2] & 0xFF;
+ int b3 = buf[3] & 0xFF;
+ int b4 = buf[4] & 0xFF;
+ int b5 = buf[5] & 0xFF;
+ int b6 = buf[6] & 0xFF;
+ int b7 = buf[7] & 0xFF;
+ return (((long)b7 << 56) +
+ ((long)b6 << 48) +
+ ((long)b5 << 40) +
+ ((long)b4 << 32) +
+ ((long)b3 << 24) +
+ (b2 << 16) +
+ (b1 << 8) +
+ (b0 << 0));
+ }
+
+ /**
+ * Reads a small amount of data from across the boundary between two blocks.
+ * The {@link #_readIndex} of this (the second) block is updated accordingly.
+ * Note- this method (and other code) assumes that the second {@link DataInputBlock}
+ * always is big enough to complete the read without being exhausted.
+ */
+ private void readSpanning(DataInputBlock prevBlock, int prevBlockAvailable, byte[] buf) {
+ System.arraycopy(prevBlock._buf, prevBlock._readIndex, buf, 0, prevBlockAvailable);
+ int secondReadLen = buf.length-prevBlockAvailable;
+ System.arraycopy(_buf, 0, buf, prevBlockAvailable, secondReadLen);
+ _readIndex = secondReadLen;
+ }
+
+ /**
+ * Reads <tt>len</tt> bytes from this block into the supplied buffer.
+ */
+ public void readFully(byte[] buf, int off, int len) {
+ System.arraycopy(_buf, _readIndex, buf, off, len);
+ _readIndex += len;
+ }
+}
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.storage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-
import java.util.Arrays;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.IntegerField;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LittleEndianConsts;
/**
* A block of document data.
*
* @author Marc Johnson (mjohnson at apache dot org)
*/
+public final class DocumentBlock extends BigBlock {
+ private static final int BLOCK_SHIFT = 9;
+ private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT;
+ private static final int BLOCK_MASK = BLOCK_SIZE-1;
-public class DocumentBlock
- extends BigBlock
-{
private static final byte _default_value = ( byte ) 0xFF;
private byte[] _data;
private int _bytes_read;
return rval;
}
- /**
- * read data from an array of DocumentBlocks
- *
- * @param blocks the blocks to read from
- * @param buffer the buffer to write the data into
- * @param offset the offset into the array of blocks to read from
- */
-
- public static void read(final DocumentBlock [] blocks,
- final byte [] buffer, final int offset)
- {
- int firstBlockIndex = offset / POIFSConstants.BIG_BLOCK_SIZE;
- int firstBlockOffset = offset % POIFSConstants.BIG_BLOCK_SIZE;
- int lastBlockIndex = (offset + buffer.length - 1)
- / POIFSConstants.BIG_BLOCK_SIZE;
-
- if (firstBlockIndex == lastBlockIndex)
- {
- System.arraycopy(blocks[ firstBlockIndex ]._data,
- firstBlockOffset, buffer, 0, buffer.length);
- }
- else
- {
- int buffer_offset = 0;
-
- System.arraycopy(blocks[ firstBlockIndex ]._data,
- firstBlockOffset, buffer, buffer_offset,
- POIFSConstants.BIG_BLOCK_SIZE
- - firstBlockOffset);
- buffer_offset += POIFSConstants.BIG_BLOCK_SIZE - firstBlockOffset;
- for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++)
- {
- System.arraycopy(blocks[ j ]._data, 0, buffer, buffer_offset,
- POIFSConstants.BIG_BLOCK_SIZE);
- buffer_offset += POIFSConstants.BIG_BLOCK_SIZE;
- }
- System.arraycopy(blocks[ lastBlockIndex ]._data, 0, buffer,
- buffer_offset, buffer.length - buffer_offset);
- }
+ public static DataInputBlock getDataInputBlock(DocumentBlock[] blocks, int offset) {
+ int firstBlockIndex = offset >> BLOCK_SHIFT;
+ int firstBlockOffset= offset & BLOCK_MASK;
+ return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
}
/* ********** START extension of BigBlock ********** */
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.storage;
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import org.apache.poi.poifs.common.POIFSConstants;
*
* @author Marc Johnson (mjohnson at apache dot org)
*/
+public final class SmallDocumentBlock implements BlockWritable, ListManagedBlock {
+ private static final int BLOCK_SHIFT = 6;
-public class SmallDocumentBlock
- implements BlockWritable, ListManagedBlock
-{
private byte[] _data;
private static final byte _default_fill = ( byte ) 0xff;
- private static final int _block_size = 64;
+ private static final int _block_size = 1 << BLOCK_SHIFT;
+ private static final int BLOCK_MASK = _block_size-1;
+
private static final int _blocks_per_big_block =
POIFSConstants.BIG_BLOCK_SIZE / _block_size;
return sdbs;
}
- /**
- * read data from an array of SmallDocumentBlocks
- *
- * @param blocks the blocks to read from
- * @param buffer the buffer to write the data into
- * @param offset the offset into the array of blocks to read from
- */
-
- public static void read(final BlockWritable [] blocks,
- final byte [] buffer, final int offset)
- {
- int firstBlockIndex = offset / _block_size;
- int firstBlockOffset = offset % _block_size;
- int lastBlockIndex = (offset + buffer.length - 1) / _block_size;
-
- if (firstBlockIndex == lastBlockIndex)
- {
- System.arraycopy(
- (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data,
- firstBlockOffset, buffer, 0, buffer.length);
- }
- else
- {
- int buffer_offset = 0;
-
- System.arraycopy(
- (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data,
- firstBlockOffset, buffer, buffer_offset,
- _block_size - firstBlockOffset);
- buffer_offset += _block_size - firstBlockOffset;
- for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++)
- {
- System.arraycopy((( SmallDocumentBlock ) blocks[ j ])._data,
- 0, buffer, buffer_offset, _block_size);
- buffer_offset += _block_size;
- }
- System.arraycopy(
- (( SmallDocumentBlock ) blocks[ lastBlockIndex ])._data, 0,
- buffer, buffer_offset, buffer.length - buffer_offset);
- }
+ public static DataInputBlock getDataInputBlock(SmallDocumentBlock[] blocks, int offset) {
+ int firstBlockIndex = offset >> BLOCK_SHIFT;
+ int firstBlockOffset= offset & BLOCK_MASK;
+ return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
}
/**
+++ /dev/null
-
-/* ====================================================================
- 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.util;
-
-import java.util.*;
-
-/**
- * A List of double's; as full an implementation of the java.util.List
- * interface as possible, with an eye toward minimal creation of
- * objects
- *
- * the mimicry of List is as follows:
- * <ul>
- * <li> if possible, operations designated 'optional' in the List
- * interface are attempted
- * <li> wherever the List interface refers to an Object, substitute
- * double
- * <li> wherever the List interface refers to a Collection or List,
- * substitute DoubleList
- * </ul>
- *
- * the mimicry is not perfect, however:
- * <ul>
- * <li> operations involving Iterators or ListIterators are not
- * supported
- * <li> remove(Object) becomes removeValue to distinguish it from
- * remove(int index)
- * <li> subList is not supported
- * </ul>
- *
- * @author Marc Johnson
- */
-
-public class DoubleList
-{
- private double[] _array;
- private int _limit;
- private static final int _default_size = 128;
-
- /**
- * create an DoubleList of default size
- */
-
- public DoubleList()
- {
- this(_default_size);
- }
-
- /**
- * create a copy of an existing DoubleList
- *
- * @param list the existing DoubleList
- */
-
- public DoubleList(final DoubleList list)
- {
- this(list._array.length);
- System.arraycopy(list._array, 0, _array, 0, _array.length);
- _limit = list._limit;
- }
-
- /**
- * create an DoubleList with a predefined initial size
- *
- * @param initialCapacity the size for the internal array
- */
-
- public DoubleList(final int initialCapacity)
- {
- _array = new double[ initialCapacity ];
- _limit = 0;
- }
-
- /**
- * add the specfied value at the specified index
- *
- * @param index the index where the new value is to be added
- * @param value the new value
- *
- * @exception IndexOutOfBoundsException if the index is out of
- * range (index < 0 || index > size()).
- */
-
- public void add(final int index, final double value)
- {
- if (index > _limit)
- {
- throw new IndexOutOfBoundsException();
- }
- else if (index == _limit)
- {
- add(value);
- }
- else
- {
-
- // index < limit -- insert into the middle
- if (_limit == _array.length)
- {
- growArray(_limit * 2);
- }
- System.arraycopy(_array, index, _array, index + 1,
- _limit - index);
- _array[ index ] = value;
- _limit++;
- }
- }
-
- /**
- * Appends the specified element to the end of this list
- *
- * @param value element to be appended to this list.
- *
- * @return true (as per the general contract of the Collection.add
- * method).
- */
-
- public boolean add(final double value)
- {
- if (_limit == _array.length)
- {
- growArray(_limit * 2);
- }
- _array[ _limit++ ] = value;
- return true;
- }
-
- /**
- * Appends all of the elements in the specified collection to the
- * end of this list, in the order that they are returned by the
- * specified collection's iterator. The behavior of this
- * operation is unspecified if the specified collection is
- * modified while the operation is in progress. (Note that this
- * will occur if the specified collection is this list, and it's
- * nonempty.)
- *
- * @param c collection whose elements are to be added to this
- * list.
- *
- * @return true if this list changed as a result of the call.
- */
-
- public boolean addAll(final DoubleList c)
- {
- if (c._limit != 0)
- {
- if ((_limit + c._limit) > _array.length)
- {
- growArray(_limit + c._limit);
- }
- System.arraycopy(c._array, 0, _array, _limit, c._limit);
- _limit += c._limit;
- }
- return true;
- }
-
- /**
- * Inserts all of the elements in the specified collection into
- * this list at the specified position. Shifts the element
- * currently at that position (if any) and any subsequent elements
- * to the right (increases their indices). The new elements will
- * appear in this list in the order that they are returned by the
- * specified collection's iterator. The behavior of this
- * operation is unspecified if the specified collection is
- * modified while the operation is in progress. (Note that this
- * will occur if the specified collection is this list, and it's
- * nonempty.)
- *
- * @param index index at which to insert first element from the
- * specified collection.
- * @param c elements to be inserted into this list.
- *
- * @return true if this list changed as a result of the call.
- *
- * @exception IndexOutOfBoundsException if the index is out of
- * range (index < 0 || index > size())
- */
-
- public boolean addAll(final int index, final DoubleList c)
- {
- if (index > _limit)
- {
- throw new IndexOutOfBoundsException();
- }
- if (c._limit != 0)
- {
- if ((_limit + c._limit) > _array.length)
- {
- growArray(_limit + c._limit);
- }
-
- // make a hole
- System.arraycopy(_array, index, _array, index + c._limit,
- _limit - index);
-
- // fill it in
- System.arraycopy(c._array, 0, _array, index, c._limit);
- _limit += c._limit;
- }
- return true;
- }
-
- /**
- * Removes all of the elements from this list. This list will be
- * empty after this call returns (unless it throws an exception).
- */
-
- public void clear()
- {
- _limit = 0;
- }
-
- /**
- * Returns true if this list contains the specified element. More
- * formally, returns true if and only if this list contains at
- * least one element e such that o == e
- *
- * @param o element whose presence in this list is to be tested.
- *
- * @return true if this list contains the specified element.
- */
-
- public boolean contains(final double o)
- {
- boolean rval = false;
-
- for (int j = 0; !rval && (j < _limit); j++)
- {
- if (_array[ j ] == o)
- {
- rval = true;
- }
- }
- return rval;
- }
-
- /**
- * Returns true if this list contains all of the elements of the
- * specified collection.
- *
- * @param c collection to be checked for containment in this list.
- *
- * @return true if this list contains all of the elements of the
- * specified collection.
- */
-
- public boolean containsAll(final DoubleList c)
- {
- boolean rval = true;
-
- if (this != c)
- {
- for (int j = 0; rval && (j < c._limit); j++)
- {
- if (!contains(c._array[ j ]))
- {
- rval = false;
- }
- }
- }
- return rval;
- }
-
- /**
- * Compares the specified object with this list for equality.
- * Returns true if and only if the specified object is also a
- * list, both lists have the same size, and all corresponding
- * pairs of elements in the two lists are equal. (Two elements e1
- * and e2 are equal if e1 == e2.) In other words, two lists are
- * defined to be equal if they contain the same elements in the
- * same order. This definition ensures that the equals method
- * works properly across different implementations of the List
- * interface.
- *
- * @param o the object to be compared for equality with this list.
- *
- * @return true if the specified object is equal to this list.
- */
-
- public boolean equals(final Object o)
- {
- boolean rval = this == o;
-
- if (!rval && (o != null) && (o.getClass() == this.getClass()))
- {
- DoubleList other = ( DoubleList ) o;
-
- if (other._limit == _limit)
- {
-
- // assume match
- rval = true;
- for (int j = 0; rval && (j < _limit); j++)
- {
- rval = _array[ j ] == other._array[ j ];
- }
- }
- }
- return rval;
- }
-
- /**
- * Returns the element at the specified position in this list.
- *
- * @param index index of element to return.
- *
- * @return the element at the specified position in this list.
- *
- * @exception IndexOutOfBoundsException if the index is out of
- * range (index < 0 || index >= size()).
- */
-
- public double get(final int index)
- {
- if (index >= _limit)
- {
- throw new IndexOutOfBoundsException();
- }
- return _array[ index ];
- }
-
- /**
- * THIS MOST LIKELY DOES NOT WORK
- * Returns the hash code value for this list. The hash code of a
- * list is defined to be the result of the following calculation:
- *
- * <code>
- * hashCode = 1;
- * Iterator i = list.iterator();
- * while (i.hasNext()) {
- * Object obj = i.next();
- * hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
- * }
- * </code>
- *
- * This ensures that list1.equals(list2) implies that
- * list1.hashCode()==list2.hashCode() for any two lists, list1 and
- * list2, as required by the general contract of Object.hashCode.
- *
- * @return the hash code value for this list.
- */
-
- public int hashCode()
- {
- int hash = 0;
-
- for (int j = 0; j < _limit; j++)
- {
- hash = (31 * hash) + ((int) _array[ j ]);
- }
- return hash;
- }
-
- /**
- * Returns the index in this list of the first occurrence of the
- * specified element, or -1 if this list does not contain this
- * element. More formally, returns the lowest index i such that
- * (o == get(i)), or -1 if there is no such index.
- *
- * @param o element to search for.
- *
- * @return the index in this list of the first occurrence of the
- * specified element, or -1 if this list does not contain
- * this element.
- */
-
- public int indexOf(final double o)
- {
- int rval = 0;
-
- for (; rval < _limit; rval++)
- {
- if (o == _array[ rval ])
- {
- break;
- }
- }
- if (rval == _limit)
- {
- rval = -1; // didn't find it
- }
- return rval;
- }
-
- /**
- * Returns true if this list contains no elements.
- *
- * @return true if this list contains no elements.
- */
-
- public boolean isEmpty()
- {
- return _limit == 0;
- }
-
- /**
- * Returns the index in this list of the last occurrence of the
- * specified element, or -1 if this list does not contain this
- * element. More formally, returns the highest index i such that
- * (o == get(i)), or -1 if there is no such index.
- *
- * @param o element to search for.
- *
- * @return the index in this list of the last occurrence of the
- * specified element, or -1 if this list does not contain
- * this element.
- */
-
- public int lastIndexOf(final double o)
- {
- int rval = _limit - 1;
-
- for (; rval >= 0; rval--)
- {
- if (o == _array[ rval ])
- {
- break;
- }
- }
- return rval;
- }
-
- /**
- * Removes the element at the specified position in this list.
- * Shifts any subsequent elements to the left (subtracts one from
- * their indices). Returns the element that was removed from the
- * list.
- *
- * @param index the index of the element to removed.
- *
- * @return the element previously at the specified position.
- *
- * @exception IndexOutOfBoundsException if the index is out of
- * range (index < 0 || index >= size()).
- */
-
- public double remove(final int index)
- {
- if (index >= _limit)
- {
- throw new IndexOutOfBoundsException();
- }
- double rval = _array[ index ];
-
- System.arraycopy(_array, index + 1, _array, index, _limit - index);
- _limit--;
- return rval;
- }
-
- /**
- * Removes the first occurrence in this list of the specified
- * element (optional operation). If this list does not contain
- * the element, it is unchanged. More formally, removes the
- * element with the lowest index i such that (o.equals(get(i)))
- * (if such an element exists).
- *
- * @param o element to be removed from this list, if present.
- *
- * @return true if this list contained the specified element.
- */
-
- public boolean removeValue(final double o)
- {
- boolean rval = false;
-
- for (int j = 0; !rval && (j < _limit); j++)
- {
- if (o == _array[ j ])
- {
- System.arraycopy(_array, j + 1, _array, j, _limit - j);
- _limit--;
- rval = true;
- }
- }
- return rval;
- }
-
- /**
- * Removes from this list all the elements that are contained in
- * the specified collection
- *
- * @param c collection that defines which elements will be removed
- * from this list.
- *
- * @return true if this list changed as a result of the call.
- */
-
- public boolean removeAll(final DoubleList c)
- {
- boolean rval = false;
-
- for (int j = 0; j < c._limit; j++)
- {
- if (removeValue(c._array[ j ]))
- {
- rval = true;
- }
- }
- return rval;
- }
-
- /**
- * Retains only the elements in this list that are contained in
- * the specified collection. In other words, removes from this
- * list all the elements that are not contained in the specified
- * collection.
- *
- * @param c collection that defines which elements this set will
- * retain.
- *
- * @return true if this list changed as a result of the call.
- */
-
- public boolean retainAll(final DoubleList c)
- {
- boolean rval = false;
-
- for (int j = 0; j < _limit; )
- {
- if (!c.contains(_array[ j ]))
- {
- remove(j);
- rval = true;
- }
- else
- {
- j++;
- }
- }
- return rval;
- }
-
- /**
- * Replaces the element at the specified position in this list
- * with the specified element
- *
- * @param index index of element to replace.
- * @param element element to be stored at the specified position.
- *
- * @return the element previously at the specified position.
- *
- * @exception IndexOutOfBoundsException if the index is out of
- * range (index < 0 || index >= size()).
- */
-
- public double set(final int index, final double element)
- {
- if (index >= _limit)
- {
- throw new IndexOutOfBoundsException();
- }
- double rval = _array[ index ];
-
- _array[ index ] = element;
- return rval;
- }
-
- /**
- * Returns the number of elements in this list. If this list
- * contains more than Doubleeger.MAX_VALUE elements, returns
- * Doubleeger.MAX_VALUE.
- *
- * @return the number of elements in this DoubleList
- */
-
- public int size()
- {
- return _limit;
- }
-
- /**
- * Returns an array containing all of the elements in this list in
- * proper sequence. Obeys the general contract of the
- * Collection.toArray method.
- *
- * @return an array containing all of the elements in this list in
- * proper sequence.
- */
-
- public double [] toArray()
- {
- double[] rval = new double[ _limit ];
-
- System.arraycopy(_array, 0, rval, 0, _limit);
- return rval;
- }
-
- /**
- * Returns an array containing all of the elements in this list in
- * proper sequence. Obeys the general contract of the
- * Collection.toArray(Object[]) method.
- *
- * @param a the array into which the elements of this list are to
- * be stored, if it is big enough; otherwise, a new array
- * is allocated for this purpose.
- *
- * @return an array containing the elements of this list.
- */
-
- public double [] toArray(final double [] a)
- {
- double[] rval;
-
- if (a.length == _limit)
- {
- System.arraycopy(_array, 0, a, 0, _limit);
- rval = a;
- }
- else
- {
- rval = toArray();
- }
- return rval;
- }
-
- private void growArray(final int new_size)
- {
- int size = (new_size == _array.length) ? new_size + 1
- : new_size;
- double[] new_array = new double[ size ];
-
- System.arraycopy(_array, 0, new_array, 0, _limit);
- _array = new_array;
- }
-} // end public class DoubleList
+++ /dev/null
-/*
-* 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.util;
-
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * Provides an interface for interacting with 2d arrays of doubles. This
- * implementation will return 0 for items not yet allocated and automatically
- * increase the array size for set operations. You never get an index out of
- * bounds.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- * @version $Id$
- */
-public class DoubleList2d
-{
- // Implemented using a List of DoubleList's.
- List rows = new ArrayList();
-
- public double get(int col, int row)
- {
- if (row >= rows.size())
- {
- return 0;
- }
- else
- {
- DoubleList cols = (DoubleList) rows.get(row);
- if (col >= cols.size())
- return 0;
- else
- return cols.get( col );
- }
- }
-
- public void set(int col, int row, double value)
- {
- resizeRows(row);
- resizeCols(row,col);
- DoubleList cols = (DoubleList) rows.get( row );
- cols.set( col, value );
- }
-
- private void resizeRows( int row )
- {
- while (rows.size() <= row)
- rows.add( new DoubleList() );
- }
-
- private void resizeCols( int row, int col )
- {
- DoubleList cols = (DoubleList) rows.get( row );
- while (cols.size() <= col)
- cols.add(0);
- }
-
-
-}
*@author Marc Johnson (mjohnson at apache dot org)
*@author Andrew Oliver (acoliver at apache dot org)
*/
-public final class LittleEndian implements LittleEndianConsts {
+public class LittleEndian implements LittleEndianConsts {
private LittleEndian() {
- // no instances of this class
+ // no instances of this class
}
-
/**
* get a short value from a byte array
*
*@param offset a starting offset into the byte array
*@return the short (16-bit) value
*/
-
- public static short getShort(final byte[] data, final int offset) {
- return (short) getNumber(data, offset, SHORT_SIZE);
+ public static short getShort(byte[] data, int offset) {
+ int b0 = data[offset] & 0xFF;
+ int b1 = data[offset+1] & 0xFF;
+ return (short) ((b1 << 8) + (b0 << 0));
}
*@param offset a starting offset into the byte array
*@return the unsigned short (16-bit) value in an integer
*/
- public static int getUShort(final byte[] data, final int offset) {
- short num = (short) getNumber(data, offset, SHORT_SIZE);
- int retNum;
- if (num < 0) {
- retNum = (Short.MAX_VALUE + 1) * 2 + num;
- } else {
- retNum = num;
- }
- return retNum;
- }
-
-
- /**
- * get a short array from a byte array.
- *
- *@param data Description of the Parameter
- *@param offset Description of the Parameter
- *@param size Description of the Parameter
- *@return The simpleShortArray value
- */
- public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) {
- short[] results = new short[size];
- for (int i = 0; i < size; i++) {
- results[i] = getShort(data, offset + 2 + (i * 2));
- }
- return results;
- }
-
-
- /**
- * get a short array from a byte array. The short array is assumed to start
- * with a word describing the length of the array.
- *
- *@param data Description of the Parameter
- *@param offset Description of the Parameter
- *@return The shortArray value
- */
- public static short[] getShortArray(final byte[] data, final int offset) {
- int size = (int) getNumber(data, offset, SHORT_SIZE);
- short[] results = getSimpleShortArray(data, offset, size);
- return results;
+ public static int getUShort(byte[] data, int offset) {
+ int b0 = data[offset] & 0xFF;
+ int b1 = data[offset+1] & 0xFF;
+ return (b1 << 8) + (b0 << 0);
}
-
/**
* get a short value from the beginning of a byte array
*
*@param data the byte array
*@return the short (16-bit) value
*/
-
- public static short getShort(final byte[] data) {
+ public static short getShort(byte[] data) {
return getShort(data, 0);
}
-
/**
* get an unsigned short value from the beginning of a byte array
*
*@param data the byte array
*@return the unsigned short (16-bit) value in an int
*/
- public static int getUShort(final byte[] data) {
+ public static int getUShort(byte[] data) {
return getUShort(data, 0);
}
-
/**
* get an int value from a byte array
*
*@param offset a starting offset into the byte array
*@return the int (32-bit) value
*/
-
- public static int getInt(final byte[] data, final int offset) {
- return (int) getNumber(data, offset, INT_SIZE);
+ public static int getInt(byte[] data, int offset) {
+ int i=offset;
+ int b0 = data[i++] & 0xFF;
+ int b1 = data[i++] & 0xFF;
+ int b2 = data[i++] & 0xFF;
+ int b3 = data[i++] & 0xFF;
+ return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
}
* get an int value from the beginning of a byte array
*
*@param data the byte array
- *@return the int (32-bit) value
+ *@return the int (32-bit) value
*/
-
- public static int getInt(final byte[] data) {
+ public static int getInt(byte[] data) {
return getInt(data, 0);
}
*@param offset a starting offset into the byte array
*@return the unsigned int (32-bit) value in a long
*/
- public static long getUInt(final byte[] data, final int offset) {
- int num = (int) getNumber(data, offset, INT_SIZE);
- long retNum;
- if (num < 0) {
- retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
- } else {
- retNum = num;
- }
- return retNum;
+ public static long getUInt(byte[] data, int offset) {
+ long retNum = getInt(data, offset);
+ return retNum & 0x00FFFFFFFF;
}
/**
*@param data the byte array
*@return the unsigned int (32-bit) value in a long
*/
- public static long getUInt(final byte[] data) {
- return getUInt(data,0);
+ public static long getUInt(byte[] data) {
+ return getUInt(data,0);
}
/**
*@param offset a starting offset into the byte array
*@return the long (64-bit) value
*/
-
- public static long getLong(final byte[] data, final int offset) {
- return getNumber(data, offset, LONG_SIZE);
- }
-
-
- /**
- * get a long value from the beginning of a byte array
- *
- *@param data the byte array
- *@return the long (64-bit) value
- */
-
- public static long getLong(final byte[] data) {
- return getLong(data, 0);
+ public static long getLong(byte[] data, int offset) {
+ long result = 0;
+
+ for (int j = offset + LONG_SIZE - 1; j >= offset; j--) {
+ result <<= 8;
+ result |= 0xff & data[j];
+ }
+ return result;
}
-
/**
* get a double value from a byte array, reads it in little endian format
* then converts the resulting revolting IEEE 754 (curse them) floating
*@param offset a starting offset into the byte array
*@return the double (64-bit) value
*/
-
- public static double getDouble(final byte[] data, final int offset) {
- return Double.longBitsToDouble(getNumber(data, offset, DOUBLE_SIZE));
- }
-
-
- /**
- * get a double value from the beginning of a byte array
- *
- *@param data the byte array
- *@return the double (64-bit) value
- */
-
- public static double getDouble(final byte[] data) {
- return getDouble(data, 0);
+ public static double getDouble(byte[] data, int offset) {
+ return Double.longBitsToDouble(getLong(data, offset));
}
-
/**
* put a short value into a byte array
*
*@param offset a starting offset into the byte array
*@param value the short (16-bit) value
*/
- public static void putShort(final byte[] data, final int offset,
- final short value) {
- putNumber(data, offset, value, SHORT_SIZE);
+ public static void putShort(byte[] data, int offset, short value) {
+ int i = offset;
+ data[i++] = (byte)((value >>> 0) & 0xFF);
+ data[i++] = (byte)((value >>> 8) & 0xFF);
}
/**
* Added for consistency with other put~() methods
*/
public static void putByte(byte[] data, int offset, int value) {
- putNumber(data, offset, value, LittleEndianConsts.BYTE_SIZE);
+ data[offset] = (byte) value;
}
/**
*
* @exception ArrayIndexOutOfBoundsException may be thrown
*/
- public static void putUShort(final byte[] data, final int offset,
- final int value)
- {
- putNumber(data, offset, value, SHORT_SIZE);
+ public static void putUShort(byte[] data, int offset, int value) {
+ int i = offset;
+ data[i++] = (byte)((value >>> 0) & 0xFF);
+ data[i++] = (byte)((value >>> 8) & 0xFF);
}
/**
*@param data the byte array
*@param value the short (16-bit) value
*/
-
- public static void putShort(final byte[] data, final short value) {
+ public static void putShort(byte[] data, short value) {
putShort(data, 0, value);
}
*@param offset a starting offset into the byte array
*@param value the int (32-bit) value
*/
-
- public static void putInt(final byte[] data, final int offset,
- final int value) {
- putNumber(data, offset, value, INT_SIZE);
+ public static void putInt(byte[] data, int offset, int value) {
+ int i = offset;
+ data[i++] = (byte)((value >>> 0) & 0xFF);
+ data[i++] = (byte)((value >>> 8) & 0xFF);
+ data[i++] = (byte)((value >>> 16) & 0xFF);
+ data[i++] = (byte)((value >>> 24) & 0xFF);
}
*@param data the byte array
*@param value the int (32-bit) value
*/
-
- public static void putInt(final byte[] data, final int value) {
+ public static void putInt(byte[] data, int value) {
putInt(data, 0, value);
}
*@param offset a starting offset into the byte array
*@param value the long (64-bit) value
*/
-
- public static void putLong(final byte[] data, final int offset,
- final long value) {
- putNumber(data, offset, value, LONG_SIZE);
- }
-
-
- /**
- * put a long value into beginning of a byte array
- *
- *@param data the byte array
- *@param value the long (64-bit) value
- */
-
- public static void putLong(final byte[] data, final long value) {
- putLong(data, 0, value);
+ public static void putLong(byte[] data, int offset, long value) {
+ int limit = LONG_SIZE + offset;
+ long v = value;
+
+ for (int j = offset; j < limit; j++) {
+ data[j] = (byte) (v & 0xFF);
+ v >>= 8;
+ }
}
*@param offset a starting offset into the byte array
*@param value the double (64-bit) value
*/
-
- public static void putDouble(final byte[] data, final int offset,
- final double value) {
+ public static void putDouble(byte[] data, int offset, double value) {
// Excel likes NaN to be a specific value.
- if (Double.isNaN(value))
- putNumber(data, offset, -276939487313920L, DOUBLE_SIZE);
- else
- putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE);
- }
-
-
- /**
- * put a double value into beginning of a byte array
- *
- *@param data the byte array
- *@param value the double (64-bit) value
- */
-
- public static void putDouble(final byte[] data, final double value) {
- putDouble(data, 0, value);
+ if (Double.isNaN(value)) {
+ putLong(data, offset, -276939487313920L);
+ } else {
+ putLong(data, offset, Double.doubleToLongBits(value));
+ }
}
*
*@author Marc Johnson (mjohnson at apache dot org)
*/
-
public static final class BufferUnderrunException extends IOException {
BufferUnderrunException() {
/**
* get a short value from an InputStream
*
- *@param stream the InputStream from which the short
- * is to be read
+ *@param stream the InputStream from which the short is to be read
*@return the short (16-bit) value
*@exception IOException will be propagated back to the caller
- *@exception BufferUnderrunException if the stream cannot provide enough
- * bytes
+ *@exception BufferUnderrunException if the stream cannot provide enough bytes
*/
public static short readShort(InputStream stream) throws IOException, BufferUnderrunException {
- return (short) readUShort(stream);
- }
+ return (short) readUShort(stream);
+ }
- public static int readUShort(InputStream stream) throws IOException, BufferUnderrunException {
+ public static int readUShort(InputStream stream) throws IOException, BufferUnderrunException {
- int ch1 = stream.read();
- int ch2 = stream.read();
- if ((ch1 | ch2) < 0) {
- throw new BufferUnderrunException();
- }
- return ((ch2 << 8) + (ch1 << 0));
- }
+ int ch1 = stream.read();
+ int ch2 = stream.read();
+ if ((ch1 | ch2) < 0) {
+ throw new BufferUnderrunException();
+ }
+ return (ch2 << 8) + (ch1 << 0);
+ }
/**
* get an int value from an InputStream
*
- *@param stream the InputStream from which the int is
- * to be read
- *@return the int (32-bit) value
- *@exception IOException will be propagated back to the caller
- *@exception BufferUnderrunException if the stream cannot provide enough
- * bytes
+ *@param stream the InputStream from which the int is to be read
+ * @return the int (32-bit) value
+ * @exception IOException will be propagated back to the caller
+ * @exception BufferUnderrunException if the stream cannot provide enough bytes
*/
- public static int readInt(final InputStream stream)
+ public static int readInt(InputStream stream)
throws IOException, BufferUnderrunException {
- int ch1 = stream.read();
- int ch2 = stream.read();
- int ch3 = stream.read();
- int ch4 = stream.read();
- if ((ch1 | ch2 | ch3 | ch4) < 0) {
- throw new BufferUnderrunException();
- }
- return ((ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0));
+ int ch1 = stream.read();
+ int ch2 = stream.read();
+ int ch3 = stream.read();
+ int ch4 = stream.read();
+ if ((ch1 | ch2 | ch3 | ch4) < 0) {
+ throw new BufferUnderrunException();
+ }
+ return (ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0);
}
/**
* get a long value from an InputStream
*
- *@param stream the InputStream from which the long
- * is to be read
- *@return the long (64-bit) value
- *@exception IOException will be propagated back to the caller
- *@exception BufferUnderrunException if the stream cannot provide enough
- * bytes
+ * @param stream the InputStream from which the long is to be read
+ * @return the long (64-bit) value
+ * @exception IOException will be propagated back to the caller
+ * @exception BufferUnderrunException if the stream cannot provide enough bytes
*/
-
- public static long readLong(final InputStream stream)
+ public static long readLong(InputStream stream)
throws IOException, BufferUnderrunException {
- int ch1 = stream.read();
- int ch2 = stream.read();
- int ch3 = stream.read();
- int ch4 = stream.read();
- int ch5 = stream.read();
- int ch6 = stream.read();
- int ch7 = stream.read();
- int ch8 = stream.read();
- if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
- throw new BufferUnderrunException();
- }
-
- return
- ((long)ch8 << 56) +
+ int ch1 = stream.read();
+ int ch2 = stream.read();
+ int ch3 = stream.read();
+ int ch4 = stream.read();
+ int ch5 = stream.read();
+ int ch6 = stream.read();
+ int ch7 = stream.read();
+ int ch8 = stream.read();
+ if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
+ throw new BufferUnderrunException();
+ }
+
+ return
+ ((long)ch8 << 56) +
((long)ch7 << 48) +
((long)ch6 << 40) +
((long)ch5 << 32) +
(ch1 << 0);
}
- /**
- * Gets the number attribute of the LittleEndian class
- *
- *@param data Description of the Parameter
- *@param offset Description of the Parameter
- *@param size Description of the Parameter
- *@return The number value
- */
- private static long getNumber(final byte[] data, final int offset,
- final int size) {
- long result = 0;
-
- for (int j = offset + size - 1; j >= offset; j--) {
- result <<= 8;
- result |= 0xff & data[j];
- }
- return result;
- }
-
-
- /**
- * Description of the Method
- *
- *@param data Description of the Parameter
- *@param offset Description of the Parameter
- *@param value Description of the Parameter
- *@param size Description of the Parameter
- */
- private static void putNumber(final byte[] data, final int offset,
- final long value, final int size) {
- int limit = size + offset;
- long v = value;
-
- for (int j = offset; j < limit; j++) {
- data[j] = (byte) (v & 0xFF);
- v >>= 8;
- }
- }
-
-
/**
* Convert an 'unsigned' byte to an integer. ie, don't carry across the
* sign.
*
- *@param b Description of the Parameter
- *@return Description of the Return Value
+ * @param b Description of the Parameter
+ * @return Description of the Return Value
*/
public static int ubyteToInt(byte b) {
- return ((b & 0x80) == 0 ? (int) b : (b & (byte) 0x7f) + 0x80);
+ return b & 0xFF;
}
/**
* get the unsigned value of a byte.
*
- *@param data the byte array.
- *@param offset a starting offset into the byte array.
- *@return the unsigned value of the byte as a 32 bit integer
+ * @param data the byte array.
+ * @param offset a starting offset into the byte array.
+ * @return the unsigned value of the byte as a 32 bit integer
*/
- public static int getUnsignedByte(final byte[] data, final int offset) {
- return (int) getNumber(data, offset, BYTE_SIZE);
- }
-
-
- /**
- * get the unsigned value of a byte.
- *
- *@param data the byte array
- *@return the unsigned value of the byte as a 32 bit integer
- */
- public static int getUnsignedByte(final byte[] data) {
- return getUnsignedByte(data, 0);
+ public static int getUnsignedByte(byte[] data, int offset) {
+ return data[offset] & 0xFF;
}
/**
* Copy a portion of a byte array
*
- *@param data the original byte array
- *@param offset Where to start copying from.
- *@param size Number of bytes to copy.
- *@return The byteArray value
- *@throws IndexOutOfBoundsException - if copying would cause access of
+ * @param data the original byte array
+ * @param offset Where to start copying from.
+ * @param size Number of bytes to copy.
+ * @return The byteArray value
+ * @throws IndexOutOfBoundsException - if copying would cause access of
* data outside array bounds.
*/
- public static byte[] getByteArray(final byte[] data, int offset, int size) {
+ public static byte[] getByteArray(byte[] data, int offset, int size) {
byte[] copy = new byte[size];
System.arraycopy(data, offset, copy, 0, size);
return copy;
}
-
- /**
- * <p>Gets an unsigned int value (8 bytes) from a byte array.</p>
- *
- * @param data the byte array
- * @param offset a starting offset into the byte array
- * @return the unsigned int (32-bit) value in a long
- */
- public static long getULong(final byte[] data, final int offset)
- {
- int num = (int) getNumber(data, offset, LONG_SIZE);
- long retNum;
- if (num < 0)
- retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
- else
- retNum = num;
- return retNum;
- }
-
}
--- /dev/null
+/* ====================================================================
+ 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.util;
+
+/**
+ * Adapts a plain byte array to {@link LittleEndianInput}
+ *
+ *
+ * @author Josh Micich
+ */
+public final class LittleEndianByteArrayInputStream implements LittleEndianInput {
+ private final byte[] _buf;
+ private final int _endIndex;
+ private int _readIndex;
+
+ public LittleEndianByteArrayInputStream(byte[] buf, int startOffset, int maxReadLen) {
+ _buf = buf;
+ _readIndex = startOffset;
+ _endIndex = startOffset + maxReadLen;
+ }
+ public LittleEndianByteArrayInputStream(byte[] buf, int startOffset) {
+ this(buf, startOffset, buf.length - startOffset);
+ }
+ public LittleEndianByteArrayInputStream(byte[] buf) {
+ this(buf, 0, buf.length);
+ }
+
+ public int available() {
+ return _endIndex - _readIndex;
+ }
+ private void checkPosition(int i) {
+ if (i > _endIndex - _readIndex) {
+ throw new RuntimeException("Buffer overrun");
+ }
+ }
+
+ public int getReadIndex() {
+ return _readIndex;
+ }
+ public byte readByte() {
+ checkPosition(1);
+ return _buf[_readIndex++];
+ }
+
+ public int readInt() {
+ checkPosition(4);
+ int i = _readIndex;
+
+ int b0 = _buf[i++] & 0xFF;
+ int b1 = _buf[i++] & 0xFF;
+ int b2 = _buf[i++] & 0xFF;
+ int b3 = _buf[i++] & 0xFF;
+ _readIndex = i;
+ return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
+ }
+ public long readLong() {
+ checkPosition(8);
+ int i = _readIndex;
+
+ int b0 = _buf[i++] & 0xFF;
+ int b1 = _buf[i++] & 0xFF;
+ int b2 = _buf[i++] & 0xFF;
+ int b3 = _buf[i++] & 0xFF;
+ int b4 = _buf[i++] & 0xFF;
+ int b5 = _buf[i++] & 0xFF;
+ int b6 = _buf[i++] & 0xFF;
+ int b7 = _buf[i++] & 0xFF;
+ _readIndex = i;
+ return (((long)b7 << 56) +
+ ((long)b6 << 48) +
+ ((long)b5 << 40) +
+ ((long)b4 << 32) +
+ ((long)b3 << 24) +
+ (b2 << 16) +
+ (b1 << 8) +
+ (b0 << 0));
+ }
+ public short readShort() {
+ return (short)readUShort();
+ }
+ public int readUByte() {
+ checkPosition(1);
+ return _buf[_readIndex++] & 0xFF;
+ }
+ public int readUShort() {
+ checkPosition(2);
+ int i = _readIndex;
+
+ int b0 = _buf[i++] & 0xFF;
+ int b1 = _buf[i++] & 0xFF;
+ _readIndex = i;
+ return (b1 << 8) + (b0 << 0);
+ }
+ public void readFully(byte[] buf, int off, int len) {
+ checkPosition(len);
+ System.arraycopy(_buf, _readIndex, _buf, off, len);
+ _readIndex+=len;
+ }
+ public void readFully(byte[] buf) {
+ readFully(buf, 0, buf.length);
+ }
+ public double readDouble() {
+ return Double.longBitsToDouble(readLong());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.util;
+
+
+/**
+ * Adapts a plain byte array to {@link LittleEndianOutput}
+ *
+ *
+ * @author Josh Micich
+ */
+public final class LittleEndianByteArrayOutputStream implements LittleEndianOutput {
+ private final byte[] _buf;
+ private final int _endIndex;
+ private int _writeIndex;
+
+ public LittleEndianByteArrayOutputStream(byte[] buf, int startOffset, int maxWriteLen) {
+ _buf = buf;
+ _writeIndex = startOffset;
+ _endIndex = startOffset + maxWriteLen;
+ }
+ public LittleEndianByteArrayOutputStream(byte[] buf, int startOffset) {
+ this(buf, startOffset, buf.length - startOffset);
+ }
+
+ private void checkPosition(int i) {
+ if (i > _endIndex - _writeIndex) {
+ throw new RuntimeException("Buffer overrun");
+ }
+ }
+
+ public void writeByte(int v) {
+ checkPosition(1);
+ _buf[_writeIndex++] = (byte)v;
+ }
+
+ public void writeDouble(double v) {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ public void writeInt(int v) {
+ checkPosition(4);
+ int i = _writeIndex;
+ _buf[i++] = (byte)((v >>> 0) & 0xFF);
+ _buf[i++] = (byte)((v >>> 8) & 0xFF);
+ _buf[i++] = (byte)((v >>> 16) & 0xFF);
+ _buf[i++] = (byte)((v >>> 24) & 0xFF);
+ _writeIndex = i;
+ }
+
+ public void writeLong(long v) {
+ writeInt((int)(v >> 0));
+ writeInt((int)(v >> 32));
+ }
+
+ public void writeShort(int v) {
+ checkPosition(2);
+ int i = _writeIndex;
+ _buf[i++] = (byte)((v >>> 0) & 0xFF);
+ _buf[i++] = (byte)((v >>> 8) & 0xFF);
+ _writeIndex = i;
+ }
+ public void write(byte[] b) {
+ int len = b.length;
+ checkPosition(len);
+ System.arraycopy(b, 0, _buf, _writeIndex, len);
+ _writeIndex += len;
+ }
+ public int getWriteIndex() {
+ return _writeIndex;
+ }
+}
* @author Josh Micich\r
*/\r
public interface LittleEndianInput {\r
+ int available();\r
byte readByte();\r
int readUByte();\r
short readShort();\r
double readDouble();\r
void readFully(byte[] buf);\r
void readFully(byte[] buf, int off, int len);\r
- String readUnicodeLEString(int nChars);\r
- String readCompressedUnicode(int nChars);\r
}\r
import java.io.InputStream;\r
\r
/**\r
+ * Wraps an {@link InputStream} providing {@link LittleEndianInput}<p/>\r
+ * \r
+ * This class does not buffer any input, so the stream read position maintained \r
+ * by this class is consistent with that of the inner stream.\r
* \r
* @author Josh Micich\r
*/\r
public LittleEndianInputStream(InputStream is) {\r
super(is);\r
}\r
-\r
+ public int available() {\r
+ try {\r
+ return super.available();\r
+ } catch (IOException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ }\r
public byte readByte() {\r
return (byte)readUByte();\r
}\r
buf[i] = (byte) ch;\r
}\r
}\r
- public String readCompressedUnicode(int nChars) {\r
- char[] buf = new char[nChars];\r
- for (int i = 0; i < buf.length; i++) {\r
- int ch;\r
- try {\r
- ch = in.read();\r
- } catch (IOException e) {\r
- throw new RuntimeException(e);\r
- }\r
- checkEOF(ch);\r
- buf[i] = (char) ch;\r
- \r
- }\r
- return new String(buf);\r
- }\r
- public String readUnicodeLEString(int nChars) {\r
- char[] buf = new char[nChars];\r
- for (int i = 0; i < buf.length; i++) {\r
- int ch;\r
- try {\r
- ch = in.read();\r
- } catch (IOException e) {\r
- throw new RuntimeException(e);\r
- }\r
- checkEOF(ch);\r
- buf[i] = (char) ch;\r
- \r
- }\r
- return new String(buf);\r
- }\r
}\r
import java.io.UnsupportedEncodingException;
import java.text.FieldPosition;
import java.text.NumberFormat;
+
+import org.apache.poi.hssf.record.RecordInputStream;
/**
- * Title: String Utility Description: Collection of string handling utilities
- *
+ * Title: String Utility Description: Collection of string handling utilities<p/>
+ *
+ * Note - none of the methods in this class deals with {@link ContinueRecord}s. For such
+ * functionality, consider using {@link RecordInputStream
+} *
*
*@author Andrew C. Oliver
*@author Sergei Kozello (sergeikozello at mail.ru)
* @param string the byte array to be converted
* @return the converted string
*/
- public static String getFromUnicodeLE(final byte[] string) {
+ public static String getFromUnicodeLE(byte[] string) {
if(string.length == 0) { return ""; }
return getFromUnicodeLE(string, 0, string.length / 2);
}
- /**
- * Given a byte array of 16-bit unicode characters in big endian
- * format (most important byte first), return a Java String representation
- * of it.
- *
- * { 0x00, 0x16 } -0x16
- *
- * @param string the byte array to be converted
- * @param offset the initial offset into the
- * byte array. it is assumed that string[ offset ] and string[ offset +
- * 1 ] contain the first 16-bit unicode character
- * @param len the length of the final string
- * @return the converted string
- * @exception ArrayIndexOutOfBoundsException if offset is out of bounds for
- * the byte array (i.e., is negative or is greater than or equal to
- * string.length)
- * @exception IllegalArgumentException if len is too large (i.e.,
- * there is not enough data in string to create a String of that
- * length)
- */
- public static String getFromUnicodeBE(
- final byte[] string,
- final int offset,
- final int len)
- throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
- if ((offset < 0) || (offset >= string.length)) {
- throw new ArrayIndexOutOfBoundsException("Illegal offset");
- }
- if ((len < 0) || (((string.length - offset) / 2) < len)) {
- throw new IllegalArgumentException("Illegal length");
- }
- try {
- return new String(string, offset, len * 2, "UTF-16BE");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Given a byte array of 16-bit unicode characters in big endian
- * format (most important byte first), return a Java String representation
- * of it.
- *
- * { 0x00, 0x16 } -0x16
- *
- * @param string the byte array to be converted
- * @return the converted string
- */
- public static String getFromUnicodeBE(final byte[] string) {
- if(string.length == 0) { return ""; }
- return getFromUnicodeBE(string, 0, string.length / 2);
- }
-
/**
* Read 8 bit data (in ISO-8859-1 codepage) into a (unicode) Java
* String and return.
throw new RuntimeException(e);
}
}
+ public static String readCompressedUnicode(LittleEndianInput in, int nChars) {
+ char[] buf = new char[nChars];
+ for (int i = 0; i < buf.length; i++) {
+ buf[i] = (char) in.readUByte();
+ }
+ return new String(buf);
+ }
+ /**
+ * InputStream <tt>in</tt> is expected to contain:
+ * <ol>
+ * <li>ushort nChars</li>
+ * <li>byte is16BitFlag</li>
+ * <li>byte[]/char[] characterData</li>
+ * </ol>
+ * For this encoding, the is16BitFlag is always present even if nChars==0.
+ */
+ public static String readUnicodeString(LittleEndianInput in) {
+
+ int nChars = in.readUShort();
+ byte flag = in.readByte();
+ if ((flag & 0x01) == 0) {
+ return readCompressedUnicode(in, nChars);
+ }
+ return readUnicodeLE(in, nChars);
+ }
+ /**
+ * OutputStream <tt>out</tt> will get:
+ * <ol>
+ * <li>ushort nChars</li>
+ * <li>byte is16BitFlag</li>
+ * <li>byte[]/char[] characterData</li>
+ * </ol>
+ * For this encoding, the is16BitFlag is always present even if nChars==0.
+ */
+ public static void writeUnicodeString(LittleEndianOutput out, String value) {
+
+ int nChars = value.length();
+ out.writeShort(nChars);
+ boolean is16Bit = hasMultibyte(value);
+ out.writeByte(is16Bit ? 0x01 : 0x00);
+ if (is16Bit) {
+ putUnicodeLE(value, out);
+ } else {
+ putCompressedUnicode(value, out);
+ }
+ }
/**
* Takes a unicode (java) string, and returns it as 8 bit data (in ISO-8859-1
}
out.write(bytes);
}
+
+ public static String readUnicodeLE(LittleEndianInput in, int nChars) {
+ char[] buf = new char[nChars];
+ for (int i = 0; i < buf.length; i++) {
+ buf[i] = (char) in.readUShort();
+ }
+ return new String(buf);
+ }
/**
* Apply printf() like formatting to a string.
result.addTestSuite(TestSheetPropertiesRecord.class);
result.addTestSuite(TestSharedFormulaRecord.class);
result.addTestSuite(TestStringRecord.class);
+ result.addTestSuite(TestStyleRecord.class);
result.addTestSuite(TestSubRecord.class);
result.addTestSuite(TestSupBookRecord.class);
result.addTestSuite(TestTableRecord.class);
};
public void testLoad() {
- CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.createWithFakeSid(data), data.length);
+ CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.createLittleEndian(data), data.length);
assertEquals( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX, record.getObjectType());
assertEquals((short) 1, record.getObjectId());
See the License for the specific language governing permissions and\r
limitations under the License.\r
==================================================================== */\r
+\r
package org.apache.poi.hssf.record;\r
\r
-import java.io.ByteArrayInputStream;\r
import java.util.Arrays;\r
\r
+import junit.framework.AssertionFailedError;\r
import junit.framework.TestCase;\r
\r
import org.apache.poi.util.HexRead;\r
public void testStore() {\r
\r
byte[] src = hr(data1);\r
- src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);\r
+// src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);\r
\r
- RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(src));\r
- in.nextRecord();\r
+ RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, src);\r
\r
- EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length-4);\r
+ EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length);\r
\r
byte[] ser = record1.serialize();\r
\r
- RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));\r
- in2.nextRecord();\r
+ RecordInputStream in2 = TestcaseRecordInputStream.create(ser);\r
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);\r
\r
- assertTrue(Arrays.equals(src, ser));\r
+ confirmData(src, ser);\r
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());\r
\r
byte[] ser2 = record1.serialize();\r
assertTrue(Arrays.equals(ser, ser2));\r
}\r
\r
+ /**\r
+ * @param expectedData does not include sid & size\r
+ * @param actualFullRecordData includes sid & size\r
+ */\r
+ private static void confirmData(byte[] expectedData, byte[] actualFullRecordData) {\r
+ assertEquals(expectedData.length, actualFullRecordData.length-4);\r
+ for (int i = 0; i < expectedData.length; i++) {\r
+ if(expectedData[i] != actualFullRecordData[i+4]) {\r
+ throw new AssertionFailedError("Difference at offset (" + i + ")");\r
+ }\r
+ }\r
+ }\r
+\r
public void testCreate() {\r
\r
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord();\r
\r
byte[] ser = record1.serialize();\r
- RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));\r
- in2.nextRecord();\r
+ RecordInputStream in2 = TestcaseRecordInputStream.create(ser);\r
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);\r
\r
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());\r
* taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).\r
*/\r
private static final byte[] data45912 = hr(\r
- "09 00 14 00 " +\r
"12 00 0B 00 F8 02 88 04 3B 00 " +\r
"00 00 00 01 00 00 00 01 " +\r
"00 00");\r
\r
public void testCameraTool_bug45912() {\r
byte[] data = data45912;\r
- RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));\r
- in.nextRecord();\r
+ RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);\r
\r
- EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length-4);\r
+ EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);\r
byte[] ser2 = rec.serialize();\r
- assertTrue(Arrays.equals(data, ser2));\r
-\r
-\r
+ confirmData(data, ser2);\r
}\r
\r
private static byte[] hr(String string) {\r
public void testWithConcat() {
// =CHOOSE(2,A2,A3,A4)
byte[] data = {
- 6, 0, 68, 0,
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
64, 0, 0, 12, 0, 12, -4, 46, 0,
30, 2, 0, // Int - 2
25, 8, 3, 0, // Attr
66, 4, 100, 0 // CHOOSE
};
- RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
- inp.nextRecord();
+ RecordInputStream inp = TestcaseRecordInputStream.create(FormatRecord.sid, data);
FormulaRecord fr = new FormulaRecord(inp);
RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data);
HyperlinkRecord link = new HyperlinkRecord(is);
byte[] bytes1 = link.serialize();
- is = new RecordInputStream(new ByteArrayInputStream(bytes1));
- is.nextRecord();
+ is = TestcaseRecordInputStream.create(bytes1);
link = new HyperlinkRecord(is);
byte[] bytes2 = link.serialize();
assertEquals(bytes1.length, bytes2.length);
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.util.LittleEndianInput;
/**
* @author Josh Micich
*/
public void testConvertSharedFormulasOperandClasses_bug45123() {
- RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
+ LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
int encodedLen = in.readUShort();
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record;\r
+\r
+import junit.framework.TestCase;\r
+/**\r
+ * \r
+ */\r
+public final class TestStyleRecord extends TestCase {\r
+ public void testUnicodeReadName() {\r
+ byte[] data = {\r
+ 17, 0, 9, 0, 1, 56, 94, -60, -119, 95, 0, 83, 0, 104, 0, 101, 0, 101, 0, 116, 0, 49, 0, 92, 40, //92, 36 \r
+ };\r
+ RecordInputStream in = TestcaseRecordInputStream.create(StyleRecord.sid, data);\r
+ StyleRecord sr = new StyleRecord(in);\r
+ assertEquals("\u5E38\u89C4_Sheet1", sr.getName()); // "<Conventional>_Sheet1"\r
+ }\r
+}\r
public void testLoad() {
- RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
- in.nextRecord();
+ RecordInputStream in = TestcaseRecordInputStream.create(data);
TextObjectRecord record = new TextObjectRecord(in);
-
assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment());
assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment());
assertEquals(true, record.isTextLocked());
\r
public void testRead() {\r
\r
- RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));\r
- is.nextRecord();\r
+ RecordInputStream is =TestcaseRecordInputStream.create(simpleData);\r
TextObjectRecord record = new TextObjectRecord(is);\r
\r
assertEquals(TextObjectRecord.sid, record.getSid());\r
assertTrue(Arrays.equals(simpleData, ser));\r
\r
//read again\r
- RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));\r
- is.nextRecord();\r
+ RecordInputStream is = TestcaseRecordInputStream.create(simpleData);\r
record = new TextObjectRecord(is);\r
}\r
\r
assertEquals(22, ser.length); // just the TXO record\r
\r
//read again\r
- RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));\r
- is.nextRecord();\r
+ RecordInputStream is = TestcaseRecordInputStream.create(ser);\r
record = new TextObjectRecord(is);\r
assertEquals(0, record.getStr().length());\r
}\r
import junit.framework.Assert;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
+import org.apache.poi.util.LittleEndianInput;
/**
* A Record Input Stream derivative that makes access to byte arrays used in the
/**
* Prepends a mock record identifier to the supplied data and opens a record input stream
*/
- public static RecordInputStream createWithFakeSid(byte[] data) {
- return create(-5555, data);
+ public static LittleEndianInput createLittleEndian(byte[] data) {
+ return new LittleEndianByteArrayInputStream(data);
}
public static RecordInputStream create(int sid, byte[] data) {
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.util.HexRead;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
/**
*
* @author Josh Micich
public void testEncode() {
int size = ConstantValueParser.getEncodedSize(SAMPLE_VALUES);
byte[] data = new byte[size];
- ConstantValueParser.encode(data, 0, SAMPLE_VALUES);
+
+ ConstantValueParser.encode(new LittleEndianByteArrayOutputStream(data, 0), SAMPLE_VALUES);
if (!Arrays.equals(data, SAMPLE_ENCODING)) {
fail("Encoding differs");
}
}
public void testDecode() {
- RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SAMPLE_ENCODING);
+ LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SAMPLE_ENCODING);
Object[] values = ConstantValueParser.parse(in, 4);
for (int i = 0; i < values.length; i++) {
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
*/
public void testReadWriteTokenValueBytes() {
- ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
+ ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
- ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
+ ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
Object[][] values = ptg.getTokenArrayValues();
assertEquals(new UnicodeString("FG"), values[1][2]);
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
- ptg.writeTokenValueBytes(outBuf, 0);
+ ptg.writeTokenValueBytes(new LittleEndianByteArrayOutputStream(outBuf, 0));
if(outBuf[0] == 4) {
throw new AssertionFailedError("Identified bug 42564b");
* Excel stores array elements column by column. This test makes sure POI does the same.
*/
public void testElementOrdering() {
- ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
- ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
+ ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
+ ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
}
public void testToFormulaString() {
- ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
+ ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
- ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
+ ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
String actualFormula;
try {
// Force encoded operand class for tArray
fullData[0] = (byte) (ArrayPtg.sid + operandClass);
- RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(fullData);
+ LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(fullData);
Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in);
assertEquals(1, ptgs.length);
import junit.framework.AssertionFailedError;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.util.HexRead;
+import org.apache.poi.util.LittleEndianInput;
/**
* Tests for {@link AttrPtg}.
*/
public void testReserializeAttrChoose() {
byte[] data = HexRead.readFromString("19, 04, 03, 00, 08, 00, 11, 00, 1A, 00, 23, 00");
- RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(data);
+ LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(data);
Ptg[] ptgs = Ptg.readTokens(data.length, in);
byte[] data2 = new byte[data.length];
try {
0,
};
- FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createWithFakeSid(fakeData) );
+ FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createLittleEndian(fakeData) );
assertEquals( "Len formula index is not 32(20H)", 0x20, ptg.getFunctionIndex() );
assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() );
assertEquals( "Function Name", "LEN", ptg.getName() );
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianInput;
/**
* Tests for {@link RefPtg}.
0x2C, 33, 44, 55, 66,
};
public void testReadWrite_tRefN_bug45091() {
- RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(tRefN_data);
+ LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(tRefN_data);
Ptg[] ptgs = Ptg.readTokens(tRefN_data.length, in);
byte[] outData = new byte[5];
Ptg.serializePtgs(ptgs, outData, 0);
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.filesystem;
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Arrays;
-import junit.framework.*;
+import junit.framework.TestCase;
import org.apache.poi.poifs.property.DirectoryProperty;
-import org.apache.poi.poifs.property.DocumentProperty;
import org.apache.poi.poifs.storage.RawDataBlock;
/**
* @author Marc Johnson
*/
-public class TestDocumentInputStream
- extends TestCase
-{
+public final class TestDocumentInputStream extends TestCase {
- /**
- * Constructor TestDocumentInputStream
- *
- * @param name
- *
- * @exception IOException
- */
-
- public TestDocumentInputStream(String name)
- throws IOException
- {
- super(name);
+ protected void setUp() throws Exception {
int blocks = (_workbook_size + 511) / 512;
_workbook_data = new byte[ 512 * blocks ];
/**
* test constructor
- *
- * @exception IOException
*/
-
- public void testConstructor()
- throws IOException
- {
+ public void testConstructor() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
assertEquals(_workbook_size, stream.available());
/**
* test available() behavior
- *
- * @exception IOException
*/
-
- public void testAvailable()
- throws IOException
- {
+ public void testAvailable() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
assertEquals(_workbook_size, stream.available());
{
stream.available();
fail("Should have caught IOException");
- }
- catch (IOException ignored)
- {
+ } catch (IllegalStateException ignored) {
// as expected
}
/**
* test mark/reset/markSupported.
- *
- * @exception IOException
*/
-
- public void testMarkFunctions()
- throws IOException
- {
+ public void testMarkFunctions() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
byte[] buffer = new byte[ _workbook_size / 5 ];
/**
* test simple read method
- *
- * @exception IOException
*/
-
- public void testReadSingleByte()
- throws IOException
- {
+ public void testReadSingleByte() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
int remaining = _workbook_size;
/**
* Test buffered read
- *
- * @exception IOException
*/
-
- public void testBufferRead()
- throws IOException
- {
+ public void testBufferRead() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
try
/**
* Test complex buffered read
- *
- * @exception IOException
*/
-
- public void testComplexBufferRead()
- throws IOException
- {
+ public void testComplexBufferRead() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
- try
- {
+ try {
stream.read(null, 0, 1);
fail("Should have caught NullPointerException");
- }
- catch (NullPointerException ignored)
- {
-
+ } catch (IllegalArgumentException ignored) {
// as expected
}
/**
* test skip
- *
- * @exception IOException
*/
-
- public void testSkip()
- throws IOException
- {
+ public void testSkip() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
assertEquals(_workbook_size, stream.available());
stream.skip(2 + ( long ) Integer.MAX_VALUE));
assertEquals(0, stream.available());
}
-
- /**
- * main method to run the unit tests
- *
- * @param ignored_args
- */
-
- public static void main(String [] ignored_args)
- {
- System.out.println(
- "Testing org.apache.poi.poifs.filesystem.DocumentInputStream");
- junit.textui.TestRunner.run(TestDocumentInputStream.class);
- }
}
*/
public final class AllPOIFSStorageTests {
- public static Test suite() {
- TestSuite result = new TestSuite("Tests for org.apache.poi.poifs.storage");
- result.addTestSuite(TestBATBlock.class);
- result.addTestSuite(TestBlockAllocationTableReader.class);
- result.addTestSuite(TestBlockAllocationTableWriter.class);
- result.addTestSuite(TestBlockListImpl.class);
- result.addTestSuite(TestDocumentBlock.class);
- result.addTestSuite(TestHeaderBlockReader.class);
- result.addTestSuite(TestHeaderBlockWriter.class);
- result.addTestSuite(TestPropertyBlock.class);
- result.addTestSuite(TestRawDataBlock.class);
- result.addTestSuite(TestRawDataBlockList.class);
- result.addTestSuite(TestSmallBlockTableReader.class);
- result.addTestSuite(TestSmallBlockTableWriter.class);
- result.addTestSuite(TestSmallDocumentBlock.class);
- result.addTestSuite(TestSmallDocumentBlockList.class);
- return result;
- }
+ public static Test suite() {
+ TestSuite result = new TestSuite(AllPOIFSStorageTests.class.getName());
+ result.addTestSuite(TestBATBlock.class);
+ result.addTestSuite(TestBlockAllocationTableReader.class);
+ result.addTestSuite(TestBlockAllocationTableWriter.class);
+ result.addTestSuite(TestBlockListImpl.class);
+ result.addTestSuite(TestDocumentBlock.class);
+ result.addTestSuite(TestHeaderBlockReader.class);
+ result.addTestSuite(TestHeaderBlockWriter.class);
+ result.addTestSuite(TestPropertyBlock.class);
+ result.addTestSuite(TestRawDataBlock.class);
+ result.addTestSuite(TestRawDataBlockList.class);
+ result.addTestSuite(TestSmallBlockTableReader.class);
+ result.addTestSuite(TestSmallBlockTableWriter.class);
+ result.addTestSuite(TestSmallDocumentBlock.class);
+ result.addTestSuite(TestSmallDocumentBlockList.class);
+ return result;
+ }
}
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.storage;
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
-import junit.framework.*;
+import junit.framework.TestCase;
/**
* Class to test DocumentBlock functionality
*
* @author Marc Johnson
*/
-
-public class TestDocumentBlock
- extends TestCase
-{
+public final class TestDocumentBlock extends TestCase {
static final private byte[] _testdata;
static
_testdata[ j ] = ( byte ) j;
}
}
- ;
-
- /**
- * Constructor TestDocumentBlock
- *
- * @param name
- */
-
- public TestDocumentBlock(String name)
- {
- super(name);
- }
/**
* Test the writing DocumentBlock constructor.
- *
- * @exception IOException
*/
-
public void testConstructor()
throws IOException
{
assertEquals(_testdata.length, size);
}
- /**
- * test static read method
- *
- * @exception IOException
- */
-
- public void testRead()
- throws IOException
- {
- DocumentBlock[] blocks = new DocumentBlock[ 4 ];
- ByteArrayInputStream input = new ByteArrayInputStream(_testdata);
-
- for (int j = 0; j < 4; j++)
- {
- blocks[ j ] = new DocumentBlock(input);
- }
- for (int j = 1; j <= 2000; j += 17)
- {
- byte[] buffer = new byte[ j ];
- int offset = 0;
-
- for (int k = 0; k < (2000 / j); k++)
- {
- DocumentBlock.read(blocks, buffer, offset);
- for (int n = 0; n < buffer.length; n++)
- {
- assertEquals("checking byte " + (k * j) + n,
- _testdata[ (k * j) + n ], buffer[ n ]);
- }
- offset += j;
- }
- }
- }
/**
* Test 'reading' constructor
- *
- * @exception IOException
*/
-
public void testReadingConstructor()
throws IOException
{
assertEquals(( byte ) 0xFF, copy[ j ]);
}
}
-
- /**
- * main method to run the unit tests
- *
- * @param ignored_args
- */
-
- public static void main(String [] ignored_args)
- {
- System.out
- .println("Testing org.apache.poi.poifs.storage.DocumentBlock");
- junit.textui.TestRunner.run(TestDocumentBlock.class);
- }
}
-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.poifs.storage;
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
-import junit.framework.*;
+import junit.framework.TestCase;
/**
* Class to test SmallDocumentBlock functionality
*
* @author Marc Johnson
*/
-
-public class TestSmallDocumentBlock
- extends TestCase
-{
+public final class TestSmallDocumentBlock extends TestCase {
static final private byte[] _testdata;
static final private int _testdata_size = 2999;
_testdata[ j ] = ( byte ) j;
}
}
- ;
-
- /**
- * constructor
- *
- * @param name
- */
-
- public TestSmallDocumentBlock(String name)
- {
- super(name);
- }
/**
* Test conversion from DocumentBlocks
- *
- * @exception IOException
*/
-
public void testConvert1()
throws IOException
{
/**
* Test conversion from byte array
- *
- * @exception IOException;
- *
- * @exception IOException
*/
-
public void testConvert2()
throws IOException
{
}
}
- /**
- * Test read method
- *
- * @exception IOException
- */
-
- public void testRead()
- throws IOException
- {
- ByteArrayInputStream stream = new ByteArrayInputStream(_testdata);
- List documents = new ArrayList();
-
- while (true)
- {
- DocumentBlock block = new DocumentBlock(stream);
-
- documents.add(block);
- if (block.partiallyRead())
- {
- break;
- }
- }
- SmallDocumentBlock[] blocks =
- SmallDocumentBlock
- .convert(( BlockWritable [] ) documents
- .toArray(new DocumentBlock[ 0 ]), _testdata_size);
-
- for (int j = 1; j <= _testdata_size; j += 38)
- {
- byte[] buffer = new byte[ j ];
- int offset = 0;
-
- for (int k = 0; k < (_testdata_size / j); k++)
- {
- SmallDocumentBlock.read(blocks, buffer, offset);
- for (int n = 0; n < buffer.length; n++)
- {
- assertEquals("checking byte " + (k * j) + n,
- _testdata[ (k * j) + n ], buffer[ n ]);
- }
- offset += j;
- }
- }
- }
-
/**
* test fill
- *
- * @exception IOException
*/
-
public void testFill()
throws IOException
{
}
}
}
-
- /**
- * main method to run the unit tests
- *
- * @param ignored_args
- */
-
- public static void main(String [] ignored_args)
- {
- System.out.println(
- "Testing org.apache.poi.poifs.storage.SmallDocumentBlock");
- junit.textui.TestRunner.run(TestSmallDocumentBlock.class);
- }
}
public final class AllPOIUtilTests {
public static Test suite() {
- TestSuite result = new TestSuite("Tests for org.apache.poi.util");
+ TestSuite result = new TestSuite(AllPOIUtilTests.class.getName());
result.addTestSuite(TestArrayUtil.class);
result.addTestSuite(TestBinaryTree.class);
result.addTestSuite(TestBitField.class);
result.addTestSuite(TestByteField.class);
- result.addTestSuite(TestDoubleList2d.class);
result.addTestSuite(TestHexDump.class);
result.addTestSuite(TestIntegerField.class);
result.addTestSuite(TestIntList.class);
+++ /dev/null
-/*
-* 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.util;
-
-import junit.framework.TestCase;
-
-/**
- * @version $Id$
- */
-public class TestDoubleList2d
- extends TestCase
-{
- public void testAccess()
- throws Exception
- {
- DoubleList2d array = new DoubleList2d();
- assertEquals( 0, array.get( 0, 0 ), 0.00001 );
- assertEquals( 0, array.get( 1, 1 ), 0.00001 );
- assertEquals( 0, array.get( 100, 100 ), 0.00001 );
- array.set( 100, 100, 999 );
- assertEquals( 999, array.get( 100, 100 ), 0.00001 );
- assertEquals( 0, array.get( 0, 0 ), 0.00001 );
- array.set( 0, 0, 999 );
- assertEquals( 999, array.get( 0, 0 ), 0.00001 );
-
- try
- {
- array.get( -1, -1 );
- fail();
- }
- catch ( ArrayIndexOutOfBoundsException e )
- {
- // pass
- }
- }
-}
* test the getDouble() method
*/
public void testGetDouble() {
- assertEquals(_doubles[0], LittleEndian.getDouble(_double_array), 0.000001 );
+ assertEquals(_doubles[0], LittleEndian.getDouble(_double_array, 0), 0.000001 );
assertEquals(_doubles[1], LittleEndian.getDouble( _double_array, LittleEndian.DOUBLE_SIZE), 0.000001);
- assertTrue(Double.isNaN(LittleEndian.getDouble(_nan_double_array)));
+ assertTrue(Double.isNaN(LittleEndian.getDouble(_nan_double_array, 0)));
- double nan = LittleEndian.getDouble(_nan_double_array);
+ double nan = LittleEndian.getDouble(_nan_double_array, 0);
byte[] data = new byte[8];
- LittleEndian.putDouble(data, nan);
+ LittleEndian.putDouble(data, 0, nan);
for ( int i = 0; i < data.length; i++ ) {
assertEquals(data[i], _nan_double_array[i]);
}
(byte) 0x02,
};
- assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata));
+ assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata, 0));
assertEquals(0x02FFFFFFFFFFFFFFL, LittleEndian.getLong(testdata, 1));
}
public void testPutDouble() {
byte[] received = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
- LittleEndian.putDouble(received, _doubles[0]);
+ LittleEndian.putDouble(received, 0, _doubles[0]);
assertTrue(compareByteArrays(received, _double_array, 0, LittleEndian.DOUBLE_SIZE));
LittleEndian.putDouble(received, 1, _doubles[1]);
byte[] expected = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
long testdata0 = 0xFFFFFFFFFFFFFF01L;
long testdata1 = 0x02FFFFFFFFFFFFFFL;
- LittleEndian.putLong(received, testdata0);
+ LittleEndian.putLong(received, 0, testdata0);
assertTrue(compareByteArrays(received, expected, 0, LittleEndian.LONG_SIZE));
LittleEndian.putLong(received, 1, testdata1);
assertTrue(compareByteArrays(received, expected, 1, LittleEndian.LONG_SIZE));
super( name );
}
- /**
- * test simple form of getFromUnicode
- */
- public void testSimpleGetFromUnicode()
- {
- byte[] test_data = new byte[32];
- int index = 0;
-
- for ( int k = 0; k < 16; k++ )
- {
- test_data[index++] = (byte) 0;
- test_data[index++] = (byte) ( 'a' + k );
- }
-
- assertEquals( "abcdefghijklmnop",
- StringUtil.getFromUnicodeBE( test_data ) );
- }
-
- /**
- * test simple form of getFromUnicode with symbols with code below and more 127
- */
- public void testGetFromUnicodeSymbolsWithCodesMoreThan127()
- {
- byte[] test_data = new byte[]{0x04, 0x22,
- 0x04, 0x35,
- 0x04, 0x41,
- 0x04, 0x42,
- 0x00, 0x20,
- 0x00, 0x74,
- 0x00, 0x65,
- 0x00, 0x73,
- 0x00, 0x74,
- };
- assertEquals( "\u0422\u0435\u0441\u0442 test",
- StringUtil.getFromUnicodeBE( test_data ) );
- }
/**
* test getFromUnicodeHigh for symbols with code below and more 127
StringUtil.getFromUnicodeLE( test_data ) );
}
- /**
- * Test more complex form of getFromUnicode
- */
- public void testComplexGetFromUnicode()
- {
- byte[] test_data = new byte[32];
- int index = 0;
- for ( int k = 0; k < 16; k++ )
- {
- test_data[index++] = (byte) 0;
- test_data[index++] = (byte) ( 'a' + k );
- }
- assertEquals( "abcdefghijklmno",
- StringUtil.getFromUnicodeBE( test_data, 0, 15 ) );
- assertEquals( "bcdefghijklmnop",
- StringUtil.getFromUnicodeBE( test_data, 2, 15 ) );
- try
- {
- StringUtil.getFromUnicodeBE( test_data, -1, 16 );
- fail( "Should have caught ArrayIndexOutOfBoundsException" );
- }
- catch ( ArrayIndexOutOfBoundsException ignored )
- {
- // as expected
- }
- try
- {
- StringUtil.getFromUnicodeBE( test_data, 32, 16 );
- fail( "Should have caught ArrayIndexOutOfBoundsException" );
- }
- catch ( ArrayIndexOutOfBoundsException ignored )
- {
- // as expected
- }
-
- try
- {
- StringUtil.getFromUnicodeBE( test_data, 1, 16 );
- fail( "Should have caught IllegalArgumentException" );
- }
- catch ( IllegalArgumentException ignored )
- {
- // as expected
- }
-
- try
- {
- StringUtil.getFromUnicodeBE( test_data, 1, -1 );
- fail( "Should have caught IllegalArgumentException" );
- }
- catch ( IllegalArgumentException ignored )
- {
- // as expected
- }
- }
/**
* Test putCompressedUnicode