Merged revisions 707486,707519,707525,707534,707541-707542,707551,707585,707729,707778,707780,707802 via svnmerge from

https://svn.apache.org/repos/asf/poi/trunk

........
  r707486 | josh | 2008-10-23 15:28:05 -0700 (Thu, 23 Oct 2008) | 1 line
  
  Converted Ptgs to use LittleEndianOutput
........
  r707519 | josh | 2008-10-23 17:58:49 -0700 (Thu, 23 Oct 2008) | 1 line
  
  Fix for unicode string bug in StyleRecord.  Improvements to WriteAccessRecord.
........
  r707525 | josh | 2008-10-23 19:08:47 -0700 (Thu, 23 Oct 2008) | 1 line
  
  Further conversion of Ptg classes to use LittleEndian input/output interfaces
........
  r707534 | josh | 2008-10-23 20:47:42 -0700 (Thu, 23 Oct 2008) | 1 line
  
  added LittleEndianByteArrayInputStream
........
  r707541 | josh | 2008-10-23 21:30:38 -0700 (Thu, 23 Oct 2008) | 1 line
  
  Removed String methods from LittleEndianInput
........
  r707542 | josh | 2008-10-23 21:40:37 -0700 (Thu, 23 Oct 2008) | 1 line
  
  removing unused code
........
  r707551 | josh | 2008-10-23 22:46:29 -0700 (Thu, 23 Oct 2008) | 1 line
  
  Simplification and code clean-up
........
  r707585 | josh | 2008-10-24 01:58:00 -0700 (Fri, 24 Oct 2008) | 1 line
  
  General clean-up in LittleEndian util class. (Some optimization, some obsolete code removal)
........
  r707729 | josh | 2008-10-24 12:25:11 -0700 (Fri, 24 Oct 2008) | 1 line
  
  Fixed test suite name
........
  r707778 | josh | 2008-10-24 16:13:44 -0700 (Fri, 24 Oct 2008) | 1 line
  
  Optimisation of RecordInputStream - removed intermediate 8K byte buffer.  Expected performance gain was not realised immediately, so LittleEndianInput stuff has been pushed down into DocumentInputStream to help.
........
  r707780 | josh | 2008-10-24 16:19:26 -0700 (Fri, 24 Oct 2008) | 1 line
  
  should have been submitted with c707778
........
  r707802 | josh | 2008-10-24 18:02:37 -0700 (Fri, 24 Oct 2008) | 1 line
  
  Further simplification to RecordInputStream.  Mostly regarding Strings, ContinueRecords and LittleEndianInput
........


git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@707945 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-10-26 07:18:17 +00:00
parent 2ccdeeaee6
commit 5965d73fd1
89 changed files with 2781 additions and 4155 deletions

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,11 +14,9 @@
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;
@ -160,17 +157,7 @@ public class TreeReaderListener implements POIFSReaderListener
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);

View File

@ -788,7 +788,7 @@ public final class Workbook implements Model {
if(r instanceof ExtendedFormatRecord) {
} else if(r instanceof StyleRecord) {
StyleRecord sr = (StyleRecord)r;
if(sr.getIndex() == xfIndex) {
if(sr.getXFIndex() == xfIndex) {
return sr;
}
} else {
@ -806,7 +806,7 @@ public final class Workbook implements Model {
// 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;
@ -1782,45 +1782,44 @@ public final class Workbook implements Model {
* @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;
}

View File

@ -18,17 +18,18 @@
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;
@ -45,8 +46,8 @@ public final class CRNRecord extends Record {
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);
@ -68,13 +69,15 @@ public final class CRNRecord extends Record {
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() {

View File

@ -27,6 +27,7 @@ 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.LittleEndianInput;
import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
@ -111,10 +112,10 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
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 {
@ -156,12 +157,7 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
}
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);

View File

@ -51,7 +51,7 @@ public final class LinkedDataFormulaField {
.append( "=" )
.append(ptg.toString() )
.append( "\n" )
.append(ptg.toDebugString() )
.append(ptg.toString())
.append( "\n" );
}
}

View File

@ -17,12 +17,12 @@
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>
@ -34,115 +34,147 @@ public final class RecordInputStream extends InputStream implements LittleEndian
/** 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 = { };
private InputStream in;
private short currentSid;
private short currentLength = -1;
private short nextSid;
/** {@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;
private final byte[] data = new byte[MAX_RECORD_DATA_SIZE];
private short recordOffset;
private long pos;
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 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);
_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;
}
byte result = data[recordOffset];
recordOffset += LittleEndian.BYTE_SIZE;
pos += LittleEndian.BYTE_SIZE;
public short getSid() {
return (short) _currentSid;
}
/**
* 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;
}
/**
*
* @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 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;
}
/** 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);
}
}
public void setAutoContinue(boolean enable) {
this.autoContinue = enable;
}
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");
}
/**
@ -150,11 +182,8 @@ public final class RecordInputStream extends InputStream implements LittleEndian
*/
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();
}
/**
@ -162,29 +191,20 @@ public final class RecordInputStream extends InputStream implements LittleEndian
*/
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();
}
/**
@ -200,22 +220,18 @@ public final class RecordInputStream extends InputStream implements LittleEndian
*/
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) {
@ -224,9 +240,8 @@ public final class RecordInputStream extends InputStream implements LittleEndian
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() {
@ -315,18 +330,19 @@ public final class RecordInputStream extends InputStream implements LittleEndian
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.
@ -350,19 +366,34 @@ public final class RecordInputStream extends InputStream implements LittleEndian
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;
}
}

View File

@ -19,332 +19,181 @@ package org.apache.poi.hssf.record;
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;
public final static short sid = 0x0293;
private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
private static final BitField is16BitUnicodeFlag = BitFieldFactory.getInstance(0x01);
public final static short STYLE_USER_DEFINED = 0;
public final static short STYLE_BUILT_IN = 1;
private static final BitField styleIndexMask = BitFieldFactory.getInstance(0x0FFF);
private static final BitField isBuiltinFlag = BitFieldFactory.getInstance(0x8000);
// shared by both user defined and builtin styles
private short field_1_xf_index; // TODO: bitfield candidate
/** shared by both user defined and built-in styles */
private int field_1_xf_index;
// only for built in styles
private byte field_2_builtin_style;
private byte field_3_outline_style_level;
// only for built in styles
private int field_2_builtin_style;
private int 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;
// only for user defined styles
private int field_3_string_options;
private String field_4_name;
public StyleRecord()
{
}
/**
* 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 (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);
}
}
}
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);
}
}
}
}
// todo sanity check exception to make sure we're one or the other
}
/**
* 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);
}
/**
* set the entire index field (including the type) (see bit setters that reference this method)
* @param index bitmask
*/
/**
* 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);
}
public void setIndex(short index)
{
field_1_xf_index = 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);
}
// bitfields for field 1
/**
* 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 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)
*/
/**
* 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 void setType(short type)
{
field_1_xf_index = setField(field_1_xf_index, type, 0x8000, 15);
}
public boolean isBuiltin(){
return isBuiltinFlag.isSet(field_1_xf_index);
}
/**
* set the actual index of the style extended format record
* @see #setIndex(short)
* @param index of the xf record
*/
/**
* get the style's name
* @return name of the style
*/
public String getName() {
return field_4_name;
}
public void setXFIndex(short index)
{
field_1_xf_index = setField(field_1_xf_index, index, 0x1FFF, 0);
}
public String toString() {
StringBuffer sb = new StringBuffer();
// end bitfields
// only for user defined records
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();
}
/**
* if this is a user defined record set the length of the style name
* @param length of the style's name
* @see #setName(String)
*/
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 void setNameLength(byte length)
{
field_2_name_length = length;
}
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;
}
/**
* set the style's name
* @param name of the style
* @see #setNameLength(byte)
*/
public int getRecordSize() {
return 4 + getDataSize();
}
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 short getSid()
{
return sid;
}
}

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.formula.Ref3DPtg;
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;
@ -209,17 +210,12 @@ public abstract class SubRecord {
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;

View File

@ -84,9 +84,11 @@ public final class SupBookRecord extends Record {
* @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;

View File

@ -25,6 +25,8 @@ 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.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianOutput;
/**
* The TXO record (0x01B6) is used to define the properties of a text box. It is
@ -129,13 +131,7 @@ public final class TextObjectRecord extends Record {
_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);
}
}
@ -154,10 +150,6 @@ public final class TextObjectRecord extends Record {
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();
@ -190,36 +182,31 @@ public final class TextObjectRecord extends Record {
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) {

View File

@ -36,13 +36,8 @@ import java.util.Collections;
* @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;
@ -53,8 +48,8 @@ public class UnicodeString
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;
@ -102,15 +97,6 @@ public class UnicodeString
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()
@ -142,9 +128,9 @@ public class UnicodeString
&& 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))
@ -186,10 +172,10 @@ public class UnicodeString
}
/**
* 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();
@ -206,35 +192,13 @@ public class UnicodeString
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);
@ -305,13 +269,8 @@ public class UnicodeString
}
/**
* 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;
@ -341,7 +300,7 @@ public class UnicodeString
}
}
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);
}
@ -392,7 +351,7 @@ public class UnicodeString
//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)
@ -497,8 +456,8 @@ public class UnicodeString
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;
@ -506,7 +465,7 @@ public class UnicodeString
stats.remainingSize = SSTRecord.MAX_RECORD_SIZE-4;
}
return offset;
}
}
public int serialize(UnicodeRecordStats stats, final int offset, byte [] data)
{
@ -514,7 +473,6 @@ public class UnicodeString
//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();
@ -568,39 +526,39 @@ public class UnicodeString
//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.
@ -686,7 +644,7 @@ public class UnicodeString
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.
*/
@ -833,13 +791,6 @@ public class UnicodeString
}
}
public short getSid()
{
return sid;
}
public int compareTo(Object obj)
{
UnicodeString str = ( UnicodeString ) obj;
@ -877,7 +828,7 @@ public class UnicodeString
}
//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))

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,111 +14,130 @@
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 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 class WriteAccessRecord
extends Record
{
public final static short sid = 0x5c;
private String field_1_username;
public WriteAccessRecord() {
setUsername("");
padding = new byte[DATA_SIZE - 3];
}
public WriteAccessRecord()
{
}
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.
public WriteAccessRecord(RecordInputStream in)
{
byte[] data = in.readRemainder();
//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);
}
}
//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) {
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);
/**
* 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")
*/
field_1_username = username;
}
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;
}
/**
* 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 toString() {
StringBuffer buffer = new StringBuffer();
public String getUsername()
{
return field_1_username;
}
buffer.append("[WRITEACCESS]\n");
buffer.append(" .name = ").append(field_1_username.toString()).append("\n");
buffer.append("[/WRITEACCESS]\n");
return buffer.toString();
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
public int serialize(int offset, byte[] data) {
String username = getUsername();
boolean is16bit = StringUtil.hasMultibyte(username);
buffer.append("[WRITEACCESS]\n");
buffer.append(" .name = ")
.append(field_1_username.toString()).append("\n");
buffer.append("[/WRITEACCESS]\n");
return buffer.toString();
}
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 serialize(int offset, byte [] data)
{
String username = getUsername();
StringBuffer temp = new StringBuffer(0x70 - (0x3));
public int getRecordSize() {
return 4 + DATA_SIZE;
}
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 short getSid() {
return sid;
}
}

View File

@ -17,10 +17,11 @@
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.
@ -47,7 +48,7 @@ public final class ConstantValueParser {
// 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);
@ -55,7 +56,7 @@ public final class ConstantValueParser {
return result;
}
private static Object readAConstantValue(RecordInputStream in) {
private static Object readAConstantValue(LittleEndianInput in) {
byte grbit = in.readByte();
switch(grbit) {
case TYPE_EMPTY:
@ -64,7 +65,7 @@ public final class ConstantValueParser {
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:
@ -77,7 +78,7 @@ public final class ConstantValueParser {
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:
@ -116,46 +117,43 @@ public final class ConstantValueParser {
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() + "'");

View File

@ -98,7 +98,6 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
buf.append(")");
}
public abstract void writeBytes(byte[] array, int offset);
public abstract int getSize();

View File

@ -17,42 +17,48 @@
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;
/**
* Common superclass of 2-D area refs
* Common superclass of 2-D area refs
*/
public abstract class Area2DPtgBase extends AreaPtgBase {
private final static int SIZE = 9;
private final static int SIZE = 9;
protected Area2DPtgBase(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);
}
protected Area2DPtgBase(RecordInputStream in) {
protected Area2DPtgBase(LittleEndianInput in) {
readCoordinates(in);
}
protected abstract byte getSid();
public final void writeBytes(byte [] array, int offset) {
LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
writeCoordinates(array, offset+1);
public final void write(LittleEndianOutput out) {
out.writeByte(getSid() + getPtgClass());
writeCoordinates(out);
}
public Area2DPtgBase(String arearef) {
super(arearef);
super(arearef);
}
public final int getSize() {
return SIZE;
}
public final String toFormulaString() {
return formatReferenceAsString();
return formatReferenceAsString();
}
public final String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
sb.append(formatReferenceAsString());
sb.append("]");
return sb.toString();
}
public final String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
sb.append(formatReferenceAsString());
sb.append("]");
return sb.toString();
}
}

View File

@ -17,11 +17,11 @@
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>
@ -44,7 +44,7 @@ public final class Area3DPtg extends AreaPtgBase implements WorkbookDependentFor
setExternSheetIndex( externIdx );
}
public Area3DPtg(RecordInputStream in) {
public Area3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readShort();
readCoordinates(in);
}
@ -67,10 +67,10 @@ public final class Area3DPtg extends AreaPtgBase implements WorkbookDependentFor
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() {

View File

@ -17,9 +17,9 @@
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.
@ -36,16 +36,16 @@ public final class AreaErrPtg extends OperandPtg {
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() {

View File

@ -17,7 +17,7 @@
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.
@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
public final class AreaNPtg extends Area2DPtgBase {
public final static short sid = 0x2D;
public AreaNPtg(RecordInputStream in) {
public AreaNPtg(LittleEndianInput in) {
super(in);
}

View File

@ -17,7 +17,7 @@
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.
@ -29,7 +29,7 @@ public final class AreaPtg extends Area2DPtgBase {
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) {

View File

@ -17,12 +17,12 @@
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.
@ -46,7 +46,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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);
@ -54,7 +54,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
protected AreaPtgBase() {
// do nothing
}
protected AreaPtgBase(String arearef) {
AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell();
@ -66,17 +66,17 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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);
@ -88,7 +88,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
setFirstRowRelative(lastRowRelative);
setLastRowRelative(firstRowRelative);
}
if (lastColumn > firstColumn) {
setFirstColumn(firstColumn);
setLastColumn(lastColumn);
@ -100,7 +100,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
setFirstColRelative(lastColRelative);
setLastColRelative(firstColRelative);
}
}
}
private static void checkColumnBounds(int colIx) {
if((colIx & 0x0FF) != colIx) {
@ -113,17 +113,17 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
}
}
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);
}
/**
@ -150,7 +150,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
}
/**
* @param rowIx last row number in the area
* @param rowIx last row number in the area
*/
public final void setLastRow(int rowIx) {
checkRowBounds(rowIx);
@ -177,7 +177,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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.
@ -192,9 +192,9 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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);
@ -235,7 +235,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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
@ -251,14 +251,14 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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
*/
@ -276,13 +276,13 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
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();
}

View File

@ -17,11 +17,11 @@
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
@ -54,7 +54,7 @@ public final class ArrayPtg extends Ptg {
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++) {
@ -108,7 +108,7 @@ public final class ArrayPtg extends Ptg {
* 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.
@ -132,7 +132,7 @@ public final class ArrayPtg extends Ptg {
if (token_3_arrayValues == null) {
sb.append(" #values#uninitialised#\n");
} else {
sb.append(" ").append(formatAsString());
sb.append(" ").append(toFormulaString());
}
return sb.toString();
}
@ -153,17 +153,16 @@ public final class ArrayPtg extends Ptg {
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);
}
@ -183,7 +182,7 @@ public final class ArrayPtg extends Ptg {
+ 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++) {
@ -201,9 +200,6 @@ public final class ArrayPtg extends Ptg {
b.append("}");
return b.toString();
}
public String toFormulaString() {
return formatAsString();
}
private static String getConstantText(Object o) {

View File

@ -17,10 +17,11 @@
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"
@ -78,7 +79,7 @@ public final class AttrPtg extends ControlPtg {
_chooseFuncOffset = -1;
}
public AttrPtg(RecordInputStream in)
public AttrPtg(LittleEndianInput in)
{
field_1_options = in.readByte();
field_2_data = in.readShort();
@ -213,19 +214,16 @@ public final class AttrPtg extends ControlPtg {
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);
}
}

View File

@ -17,42 +17,43 @@
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 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(LittleEndianInput in) {
_value = (in.readByte() == 1);
}
public BoolPtg(String formulaToken) {
_value = (formulaToken.equalsIgnoreCase("TRUE"));
}
public BoolPtg(String formulaToken) {
_value = (formulaToken.equalsIgnoreCase("TRUE"));
}
public boolean getValue() {
return _value;
}
public boolean getValue() {
return _value;
}
public void writeBytes(byte [] array, int offset) {
array[ offset + 0 ] = sid;
array[ offset + 1 ] = (byte) (_value ? 1 : 0);
}
public void write(LittleEndianOutput out) {
out.writeByte(sid + getPtgClass());
out.writeByte(_value ? 1 : 0);
}
public int getSize() {
return SIZE;
}
public int getSize() {
return SIZE;
}
public String toFormulaString() {
return _value ? "TRUE" : "FALSE";
}
public String toFormulaString() {
return _value ? "TRUE" : "FALSE";
}
}

View File

@ -17,11 +17,11 @@
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>
@ -42,7 +42,7 @@ public final class DeletedArea3DPtg extends OperandPtg implements WorkbookDepend
unused2 = 0;
}
public DeletedArea3DPtg(RecordInputStream in) {
public DeletedArea3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readUShort();
unused1 = in.readInt();
unused2 = in.readInt();
@ -60,10 +60,10 @@ public final class DeletedArea3DPtg extends OperandPtg implements WorkbookDepend
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);
}
}

View File

@ -18,11 +18,11 @@
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>
@ -37,7 +37,7 @@ public final class DeletedRef3DPtg extends OperandPtg implements WorkbookDepende
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();
}
@ -60,9 +60,9 @@ public final class DeletedRef3DPtg extends OperandPtg implements WorkbookDepende
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);
}
}

View File

@ -17,8 +17,9 @@
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)
@ -57,14 +58,13 @@ public final class ErrPtg extends ScalarConstantPtg {
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() {

View File

@ -18,8 +18,8 @@
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;
/**
*
@ -33,42 +33,41 @@ public final class ExpPtg extends ControlPtg {
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();
}
}
}

View File

@ -16,10 +16,10 @@
==================================================================== */
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
@ -35,7 +35,7 @@ public final class FuncPtg extends AbstractFunctionPtg {
/**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();
@ -55,9 +55,9 @@ public final class FuncPtg extends AbstractFunctionPtg {
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() {

View File

@ -16,10 +16,10 @@
==================================================================== */
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;
/**
*
@ -33,7 +33,7 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
/**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);
@ -64,10 +64,10 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
}
}
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() {

View File

@ -17,58 +17,60 @@
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());
}
}

View File

@ -17,54 +17,46 @@
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;
}
}

View File

@ -17,68 +17,45 @@
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;
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 */
/** Creates new MemAreaPtg */
public MemAreaPtg()
{
}
public MemAreaPtg(int subexLen) {
field_1_reserved = 0;
field_2_subex_len = subexLen;
}
public MemAreaPtg(RecordInputStream in)
{
field_1_reserved = in.readInt();
field_2_subex_len = in.readShort();
}
public MemAreaPtg(LittleEndianInput in) {
field_1_reserved = in.readInt();
field_2_subex_len = in.readShort();
}
public void setReserved(int res)
{
field_1_reserved = res;
}
public void write(LittleEndianOutput out) {
out.writeByte(sid + getPtgClass());
out.writeInt(field_1_reserved);
out.writeShort(field_2_subex_len);
}
public int getReserved()
{
return field_1_reserved;
}
public int getSize() {
return SIZE;
}
public void setSubexpressionLength(short subexlen)
{
field_2_subex_len = subexlen;
}
public String toFormulaString() {
return ""; // TODO: Not sure how to format this. -- DN
}
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 byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -17,36 +17,41 @@
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 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 final class MemErrPtg extends MemAreaPtg {
public final static short sid = 0x27;
public MemErrPtg(LittleEndianInput in) {
field_1_reserved = in.readInt();
field_2_subex_len = in.readShort();
}
/** Creates new MemErrPtg */
public void write(LittleEndianOutput out) {
out.writeByte(sid + getPtgClass());
out.writeInt(field_1_reserved);
out.writeShort(field_2_subex_len);
}
public MemErrPtg()
{
}
public int getSize() {
return SIZE;
}
public MemErrPtg(RecordInputStream in) {
super(in);
}
public String toFormulaString() {
return "ERR#";
}
public void writeBytes(byte [] array, int offset) {
super.writeBytes(array, offset);
array[offset] = (byte) (sid + getPtgClass());
}
public String toFormulaString()
{
return "ERR#";
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -17,56 +17,51 @@
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());
}
public MemFuncPtg(int subExprLen) {
field_1_len_ref_subexpression = subExprLen;
/**
* Creates new function pointer from a byte array usually called while
* reading an excel file.
*/
public MemFuncPtg(LittleEndianInput in) {
this(in.readUShort());
}
public int getSize()
{
return 3;
}
public MemFuncPtg(int subExprLen) {
field_1_len_ref_subexpression = subExprLen;
}
public void writeBytes( byte[] array, int offset )
{
array[offset + 0] = sid ;
LittleEndian.putUShort( array, offset + 1, field_1_len_ref_subexpression );
}
public int getSize() {
return 3;
}
public String toFormulaString()
{
return "";
}
public void write(LittleEndianOutput out) {
out.writeByte(sid + getPtgClass());
out.writeShort(field_1_len_ref_subexpression);
}
public byte getDefaultOperandClass()
{
return Ptg.CLASS_REF;
}
public String toFormulaString() {
return "";
}
public int getNumberOfOperands()
{
return field_1_len_ref_subexpression;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public int getLenRefSubexpression()
{
return field_1_len_ref_subexpression;
}
public int getNumberOfOperands() {
return field_1_len_ref_subexpression;
}
public int getLenRefSubexpression() {
return field_1_len_ref_subexpression;
}
}

View File

@ -17,32 +17,35 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndianOutput;
/**
* Missing Function Arguments
*
*
* Avik Sengupta &lt;avik at apache.org&gt;
*
* @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;
}
private final static int SIZE = 1;
public final static byte sid = 0x16;
public int getSize() {
return SIZE;
}
public String toFormulaString() {
return " ";
}
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 " ";
}
}

View File

@ -17,63 +17,63 @@
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;
}
}

View File

@ -17,10 +17,10 @@
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;
/**
*
@ -51,15 +51,15 @@ public final class NameXPtg extends OperandPtg implements WorkbookDependentFormu
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() {

View File

@ -17,55 +17,55 @@
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);
}
}

View File

@ -15,46 +15,44 @@
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 &lt;lists@aviksengupta.com&gt;
* 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 &lt;lists@aviksengupta.com&gt; 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;
}
private final static int SIZE = 1;
public final static byte sid = 0x15;
public String toFormulaString()
{
return "()";
}
public static final ControlPtg instance = new ParenthesisPtg();
public String toFormulaString(String[] operands) {
return "("+operands[0]+")";
}
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] + ")";
}
}

View File

@ -20,8 +20,8 @@ package org.apache.poi.hssf.record.formula;
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;
/**
@ -48,12 +48,12 @@ public abstract class Ptg implements Cloneable {
* 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);
@ -77,7 +77,7 @@ public abstract class Ptg implements Cloneable {
return toPtgArray(temp);
}
public static Ptg createPtg(RecordInputStream in) {
public static Ptg createPtg(LittleEndianInput in) {
byte id = in.readByte();
if (id < 0x20) {
@ -97,7 +97,7 @@ public abstract class Ptg implements Cloneable {
return retval;
}
private static Ptg createClassifiedPtg(byte id, RecordInputStream in) {
private static Ptg createClassifiedPtg(byte id, LittleEndianInput in) {
int baseId = id & 0x1F | 0x20;
@ -126,9 +126,9 @@ public abstract class Ptg implements Cloneable {
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
@ -228,32 +228,30 @@ public abstract class Ptg implements Cloneable {
* @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;
}
/**
@ -266,38 +264,12 @@ public abstract class Ptg implements Cloneable {
*/
// 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

View File

@ -17,6 +17,8 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndianOutput;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
@ -40,9 +42,8 @@ public final class RangePtg extends OperationPtg {
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()

View File

@ -17,51 +17,55 @@
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();
}
}

View File

@ -17,12 +17,12 @@
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>
@ -41,7 +41,7 @@ public final class Ref3DPtg extends RefPtgBase implements WorkbookDependentFormu
/** Creates new AreaPtg */
public Ref3DPtg() {}
public Ref3DPtg(RecordInputStream in) {
public Ref3DPtg(LittleEndianInput in) {
field_1_index_extern_sheet = in.readShort();
readCoordinates(in);
}
@ -66,10 +66,10 @@ public final class Ref3DPtg extends RefPtgBase implements WorkbookDependentFormu
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() {

View File

@ -17,10 +17,9 @@
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
@ -35,7 +34,7 @@ public final class RefErrorPtg extends OperandPtg {
public RefErrorPtg() {
field_1_reserved = 0;
}
public RefErrorPtg(RecordInputStream in) {
public RefErrorPtg(LittleEndianInput in) {
field_1_reserved = in.readInt();
}
@ -43,9 +42,9 @@ public final class RefErrorPtg extends OperandPtg {
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()

View File

@ -17,7 +17,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndianInput;
/**
* RefNPtg
@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
public final class RefNPtg extends Ref2DPtgBase {
public final static byte sid = 0x2C;
public RefNPtg(RecordInputStream in) {
public RefNPtg(LittleEndianInput in) {
super(in);
}

View File

@ -17,7 +17,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndianInput;
/**
* ReferencePtg - handles references (such as A1, A2, IA4)
@ -39,7 +39,7 @@ public final class RefPtg extends Ref2DPtgBase {
super(row, column, isRowRelative, isColumnRelative);
}
public RefPtg(RecordInputStream in) {
public RefPtg(LittleEndianInput in) {
super(in);
}

View File

@ -17,112 +17,114 @@
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;
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);
/** 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
}
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());
}
/**
* 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 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);
}
protected final void readCoordinates(LittleEndianInput in) {
field_1_row = in.readUShort();
field_2_col = in.readUShort();
}
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;
}
protected final void writeCoordinates(LittleEndianOutput out) {
out.writeShort(field_1_row);
out.writeShort(field_2_col);
}
/**
* @return the row number as an int, between 0 and 65535
*/
public final int getRow(){
return field_1_row;
}
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;
}
public final boolean isRowRelative() {
return rowRelative.isSet(field_2_col);
}
/**
* @return the row number as an int, between 0 and 65535
*/
public final int getRow() {
return field_1_row;
}
public final void setRowRelative(boolean rel) {
field_2_col=rowRelative.setBoolean(field_2_col,rel);
}
public final boolean isRowRelative() {
return rowRelative.isSet(field_2_col);
}
public final boolean isColRelative() {
return colRelative.isSet(field_2_col);
}
public final void setRowRelative(boolean rel) {
field_2_col = rowRelative.setBoolean(field_2_col, rel);
}
public final void setColRelative(boolean rel) {
field_2_col=colRelative.setBoolean(field_2_col,rel);
}
public final boolean isColRelative() {
return colRelative.isSet(field_2_col);
}
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 void setColRelative(boolean rel) {
field_2_col = colRelative.setBoolean(field_2_col, rel);
}
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 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 byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
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;
}
}

View File

@ -17,9 +17,8 @@
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;
/**
@ -31,29 +30,26 @@ 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);
}
}
/**
@ -69,32 +65,27 @@ public final class StringPtg extends ScalarConstantPtg {
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() {

View File

@ -18,8 +18,8 @@
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.
@ -43,15 +43,15 @@ public final class TblPtg extends ControlPtg {
/** 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() {

View File

@ -17,6 +17,8 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndianOutput;
/**
* @author Glen Stampoultzis (glens at apache.org)
@ -39,9 +41,8 @@ public final class UnionPtg extends OperationPtg {
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()

View File

@ -16,7 +16,7 @@
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndianOutput;
/**
*
@ -25,22 +25,17 @@ import org.apache.poi.hssf.record.RecordInputStream;
*/
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()
@ -55,8 +50,6 @@ public class UnknownPtg extends Ptg {
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new UnknownPtg();
return this;
}
}

View File

@ -17,18 +17,19 @@
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;
@ -38,8 +39,8 @@ public abstract class ValueOperatorPtg extends OperationPtg {
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();
@ -47,8 +48,9 @@ public abstract class ValueOperatorPtg extends OperationPtg {
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");
}
}

View File

@ -975,7 +975,7 @@ public class HSSFCellStyle implements CellStyle
if(sr == null) {
return null;
}
if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
if(sr.isBuiltin()) {
return null;
}
return sr.getName();
@ -990,7 +990,7 @@ public class HSSFCellStyle implements CellStyle
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);

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,437 +14,314 @@
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 final class DocumentInputStream extends InputStream implements LittleEndianInput {
/** returned by read operations if we're at end of document */
private static final int EOF = -1;
public class DocumentInputStream
extends InputStream
{
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 offset into the Document */
private int _current_offset;
// current marked offset into the Document (used by mark and
// reset)
private int _marked_offset;
/** current marked offset into the Document (used by mark and reset) */
private int _marked_offset;
// the Document's size
private int _document_size;
/** the Document's size */
private int _document_size;
// have we been closed?
private boolean _closed;
/** have we been closed? */
private boolean _closed;
// the actual Document
private POIFSDocument _document;
/** the actual Document */
private POIFSDocument _document;
// buffer used to read one byte at a time
private byte[] _tiny_buffer;
/** the data block containing the current stream pointer */
private DataInputBlock _currentBlock;
// 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(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 DocumentEntry
*
* @param document the DocumentEntry to be read
*
* @exception IOException if the DocumentEntry cannot be opened
* (like, maybe it has been deleted?)
*/
/**
* 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 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");
}
}
public int available() {
if (_closed) {
throw new IllegalStateException("cannot perform requested operation on a closed stream");
}
return _document_size - _current_offset;
}
/**
* 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 void close() {
_closed = true;
}
public DocumentInputStream(final POIFSDocument document)
throws IOException
{
_current_offset = 0;
_marked_offset = 0;
_document_size = document.getSize();
_closed = false;
_tiny_buffer = null;
_document = document;
}
public void mark(int ignoredReadlimit) {
_marked_offset = _current_offset;
}
/**
* 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)
*/
/**
* Tests if this input stream supports the mark and reset methods.
*
* @return <code>true</code> always
*/
public boolean markSupported() {
return true;
}
public int available()
throws IOException
{
dieIfClosed();
return _document_size - _current_offset;
}
private DataInputBlock getDataInputBlock(int offset) {
return _document.getDataInputBlock(offset);
}
/**
* Closes this input stream and releases any system resources
* associated with the stream.
*
* @exception IOException
*/
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 void close()
throws IOException
{
_closed = true;
}
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
/**
* 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 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;
}
public void mark(int ignoredReadlimit)
{
_marked_offset = _current_offset;
}
/**
* 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);
}
/**
* Tests if this input stream supports the mark and reset methods.
*
* @return true
*/
public long skip(long n) throws IOException {
dieIfClosed();
if (n < 0) {
return 0;
}
int new_offset = _current_offset + (int) n;
public boolean markSupported()
{
return true;
}
if (new_offset < _current_offset) {
/**
* 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
*/
// 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;
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;
}
_current_offset = new_offset;
_currentBlock = getDataInputBlock(_current_offset);
return rval;
}
/**
* 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
*/
private void dieIfClosed() throws IOException {
if (_closed) {
throw new IOException("cannot perform requested operation on a closed stream");
}
}
public int read(final byte [] b)
throws IOException, NullPointerException
{
return read(b, 0, b.length);
}
private boolean atEOD() {
return _current_offset == _document_size;
}
/**
* 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
*/
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 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);
public byte readByte() {
return (byte) readUByte();
}
if ((off == 0) && (limit == b.length))
{
_document.read(b, _current_offset);
}
else
{
byte[] buffer = new byte[ limit ];
public double readDouble() {
return Double.longBitsToDouble(readLong());
}
_document.read(buffer, _current_offset);
System.arraycopy(buffer, 0, b, off, limit);
}
_current_offset += limit;
return limit;
}
public void readFully(byte[] buf) {
readFully(buf, 0, buf.length);
}
/**
* 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 short readShort() {
return (short) readUShort();
}
public void reset()
{
_current_offset = _marked_offset;
}
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();
}
}
}
/**
* 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 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 long skip(final long n)
throws IOException
{
dieIfClosed();
if (n < 0)
{
return 0;
}
int new_offset = _current_offset + ( int ) n;
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;
}
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 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,186 @@
/* ====================================================================
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;
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,31 +14,27 @@
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;
@ -161,45 +156,10 @@ public class DocumentBlock
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 ********** */

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,13 +14,15 @@
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;
@ -31,13 +32,14 @@ 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;
@ -178,46 +180,10 @@ public class SmallDocumentBlock
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);
}
/**

View File

@ -1,642 +0,0 @@
/* ====================================================================
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

View File

@ -1,74 +0,0 @@
/*
* 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);
}
}

View File

@ -28,13 +28,12 @@ import java.io.InputStream;
*@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
*
@ -42,9 +41,10 @@ public final class LittleEndian implements LittleEndianConsts {
*@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));
}
@ -55,73 +55,32 @@ public final class LittleEndian implements LittleEndianConsts {
*@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;
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 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;
}
/**
* 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
*
@ -129,9 +88,13 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
}
@ -139,10 +102,9 @@ public final class LittleEndian implements LittleEndianConsts {
* 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);
}
@ -154,15 +116,9 @@ public final class LittleEndian implements LittleEndianConsts {
*@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;
}
/**
@ -171,8 +127,8 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
}
/**
@ -182,24 +138,16 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
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 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);
}
/**
* get a double value from a byte array, reads it in little endian format
* then converts the resulting revolting IEEE 754 (curse them) floating
@ -209,24 +157,10 @@ public final class LittleEndian implements LittleEndianConsts {
*@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));
public static double getDouble(byte[] data, int offset) {
return Double.longBitsToDouble(getLong(data, offset));
}
/**
* 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);
}
/**
* put a short value into a byte array
*
@ -234,9 +168,10 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
}
/**
@ -247,7 +182,7 @@ public final class LittleEndian implements LittleEndianConsts {
* 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;
}
/**
@ -259,10 +194,10 @@ public final class LittleEndian implements LittleEndianConsts {
*
* @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);
}
/**
@ -271,8 +206,7 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
}
@ -284,10 +218,12 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
}
@ -297,8 +233,7 @@ public final class LittleEndian implements LittleEndianConsts {
*@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);
}
@ -310,22 +245,14 @@ public final class LittleEndian implements LittleEndianConsts {
*@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;
}
}
@ -336,26 +263,13 @@ public final class LittleEndian implements LittleEndianConsts {
*@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));
}
}
@ -364,7 +278,6 @@ public final class LittleEndian implements LittleEndianConsts {
*
*@author Marc Johnson (mjohnson at apache dot org)
*/
public static final class BufferUnderrunException extends IOException {
BufferUnderrunException() {
@ -376,79 +289,72 @@ public final class LittleEndian implements LittleEndianConsts {
/**
* 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) +
@ -458,114 +364,44 @@ public final class LittleEndian implements LittleEndianConsts {
(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;
}
}

View File

@ -0,0 +1,120 @@
/* ====================================================================
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());
}
}

View File

@ -0,0 +1,87 @@
/* ====================================================================
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;
}
}

View File

@ -21,6 +21,7 @@ package org.apache.poi.util;
* @author Josh Micich
*/
public interface LittleEndianInput {
int available();
byte readByte();
int readUByte();
short readShort();
@ -30,6 +31,4 @@ public interface LittleEndianInput {
double readDouble();
void readFully(byte[] buf);
void readFully(byte[] buf, int off, int len);
String readUnicodeLEString(int nChars);
String readCompressedUnicode(int nChars);
}

View File

@ -22,6 +22,10 @@ import java.io.IOException;
import java.io.InputStream;
/**
* Wraps an {@link InputStream} providing {@link LittleEndianInput}<p/>
*
* This class does not buffer any input, so the stream read position maintained
* by this class is consistent with that of the inner stream.
*
* @author Josh Micich
*/
@ -29,7 +33,13 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
public LittleEndianInputStream(InputStream is) {
super(is);
}
public int available() {
try {
return super.available();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public byte readByte() {
return (byte)readUByte();
}
@ -131,34 +141,4 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
buf[i] = (byte) ch;
}
}
public String readCompressedUnicode(int nChars) {
char[] buf = new char[nChars];
for (int i = 0; i < buf.length; i++) {
int ch;
try {
ch = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(ch);
buf[i] = (char) ch;
}
return new String(buf);
}
public String readUnicodeLEString(int nChars) {
char[] buf = new char[nChars];
for (int i = 0; i < buf.length; i++) {
int ch;
try {
ch = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(ch);
buf[i] = (char) ch;
}
return new String(buf);
}
}

View File

@ -20,9 +20,14 @@ package org.apache.poi.util;
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)
@ -84,64 +89,11 @@ public class StringUtil {
* @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.
@ -163,6 +115,52 @@ public class StringUtil {
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
@ -220,6 +218,14 @@ public class StringUtil {
}
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.

View File

@ -100,6 +100,7 @@ public final class AllRecordTests {
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);

View File

@ -37,7 +37,7 @@ public final class TestCommonObjectDataSubRecord extends TestCase {
};
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());

View File

@ -14,11 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.util.HexRead;
@ -37,33 +38,43 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
public void testStore() {
byte[] src = hr(data1);
src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);
// src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(src));
in.nextRecord();
RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, src);
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length-4);
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length);
byte[] ser = record1.serialize();
RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));
in2.nextRecord();
RecordInputStream in2 = TestcaseRecordInputStream.create(ser);
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
assertTrue(Arrays.equals(src, ser));
confirmData(src, ser);
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
byte[] ser2 = record1.serialize();
assertTrue(Arrays.equals(ser, ser2));
}
/**
* @param expectedData does not include sid & size
* @param actualFullRecordData includes sid & size
*/
private static void confirmData(byte[] expectedData, byte[] actualFullRecordData) {
assertEquals(expectedData.length, actualFullRecordData.length-4);
for (int i = 0; i < expectedData.length; i++) {
if(expectedData[i] != actualFullRecordData[i+4]) {
throw new AssertionFailedError("Difference at offset (" + i + ")");
}
}
}
public void testCreate() {
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord();
byte[] ser = record1.serialize();
RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));
in2.nextRecord();
RecordInputStream in2 = TestcaseRecordInputStream.create(ser);
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
@ -78,21 +89,17 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
* taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).
*/
private static final byte[] data45912 = hr(
"09 00 14 00 " +
"12 00 0B 00 F8 02 88 04 3B 00 " +
"00 00 00 01 00 00 00 01 " +
"00 00");
public void testCameraTool_bug45912() {
byte[] data = data45912;
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
in.nextRecord();
RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);
EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length-4);
EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);
byte[] ser2 = rec.serialize();
assertTrue(Arrays.equals(data, ser2));
confirmData(data, ser2);
}
private static byte[] hr(String string) {

View File

@ -119,7 +119,6 @@ public final class TestFormulaRecord extends TestCase {
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
@ -134,8 +133,7 @@ public final class TestFormulaRecord extends TestCase {
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);

View File

@ -239,8 +239,7 @@ public final class TestHyperlinkRecord extends TestCase {
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);

View File

@ -23,6 +23,7 @@ import junit.framework.TestCase;
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
@ -59,7 +60,7 @@ public final class TestSharedFormulaRecord extends TestCase {
*/
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);

View File

@ -0,0 +1,33 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import junit.framework.TestCase;
/**
*
*/
public final class TestStyleRecord extends TestCase {
public void testUnicodeReadName() {
byte[] data = {
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
};
RecordInputStream in = TestcaseRecordInputStream.create(StyleRecord.sid, data);
StyleRecord sr = new StyleRecord(in);
assertEquals("\u5E38\u89C4_Sheet1", sr.getName()); // "<Conventional>_Sheet1"
}
}

View File

@ -55,11 +55,9 @@ public final class TestTextObjectBaseRecord extends TestCase {
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());

View File

@ -52,8 +52,7 @@ public final class TestTextObjectRecord extends TestCase {
public void testRead() {
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
is.nextRecord();
RecordInputStream is =TestcaseRecordInputStream.create(simpleData);
TextObjectRecord record = new TextObjectRecord(is);
assertEquals(TextObjectRecord.sid, record.getSid());
@ -79,8 +78,7 @@ public final class TestTextObjectRecord extends TestCase {
assertTrue(Arrays.equals(simpleData, ser));
//read again
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
is.nextRecord();
RecordInputStream is = TestcaseRecordInputStream.create(simpleData);
record = new TextObjectRecord(is);
}
@ -101,8 +99,7 @@ public final class TestTextObjectRecord extends TestCase {
assertEquals(22, ser.length); // just the TXO record
//read again
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));
is.nextRecord();
RecordInputStream is = TestcaseRecordInputStream.create(ser);
record = new TextObjectRecord(is);
assertEquals(0, record.getStr().length());
}

View File

@ -23,6 +23,8 @@ import java.io.InputStream;
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
@ -40,8 +42,8 @@ public final class TestcaseRecordInputStream {
/**
* 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) {

View File

@ -21,11 +21,12 @@ import java.util.Arrays;
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
@ -52,14 +53,15 @@ public final class TestConstantValueParser extends TestCase {
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++) {

View File

@ -24,6 +24,8 @@ 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.HSSFWorkbook;
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianInput;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
@ -54,9 +56,9 @@ public final class TestArrayPtg extends 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();
@ -70,7 +72,7 @@ public final class TestArrayPtg extends TestCase {
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");
@ -82,8 +84,8 @@ public final class TestArrayPtg extends TestCase {
* 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());
@ -113,9 +115,9 @@ public final class TestArrayPtg extends TestCase {
}
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 {
@ -146,7 +148,7 @@ public final class TestArrayPtg extends TestCase {
// 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);

View File

@ -21,9 +21,9 @@ import java.util.Arrays;
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}.
@ -37,7 +37,7 @@ public final class TestAttrPtg extends AbstractPtgTestCase {
*/
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 {

View File

@ -34,7 +34,7 @@ public final class TestFuncPtg extends TestCase {
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() );

View File

@ -23,10 +23,10 @@ import junit.framework.AssertionFailedError;
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}.
@ -94,7 +94,7 @@ public final class TestReferencePtg extends TestCase {
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);

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,18 +14,16 @@
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.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.*;
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;
/**
@ -35,22 +32,9 @@ 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 ];
@ -86,13 +70,8 @@ public class TestDocumentInputStream
/**
* test constructor
*
* @exception IOException
*/
public void testConstructor()
throws IOException
{
public void testConstructor() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
assertEquals(_workbook_size, stream.available());
@ -100,13 +79,8 @@ public class TestDocumentInputStream
/**
* 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());
@ -115,9 +89,7 @@ public class TestDocumentInputStream
{
stream.available();
fail("Should have caught IOException");
}
catch (IOException ignored)
{
} catch (IllegalStateException ignored) {
// as expected
}
@ -125,13 +97,8 @@ public class TestDocumentInputStream
/**
* 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 ];
@ -169,13 +136,8 @@ public class TestDocumentInputStream
/**
* 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;
@ -205,13 +167,8 @@ public class TestDocumentInputStream
/**
* Test buffered read
*
* @exception IOException
*/
public void testBufferRead()
throws IOException
{
public void testBufferRead() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
try
@ -275,23 +232,14 @@ public class TestDocumentInputStream
/**
* 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
}
@ -391,13 +339,8 @@ public class TestDocumentInputStream
/**
* test skip
*
* @exception IOException
*/
public void testSkip()
throws IOException
{
public void testSkip() throws IOException {
DocumentInputStream stream = new DocumentInputStream(_workbook);
assertEquals(_workbook_size, stream.available());
@ -422,17 +365,4 @@ public class TestDocumentInputStream
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);
}
}

View File

@ -26,22 +26,22 @@ import junit.framework.TestSuite;
*/
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;
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,25 +14,21 @@
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
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
@ -44,25 +39,10 @@ public class TestDocumentBlock
_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
{
@ -88,46 +68,10 @@ public class TestDocumentBlock
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
{
@ -164,17 +108,4 @@ public class TestDocumentBlock
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);
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,25 +14,24 @@
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.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
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;
@ -45,25 +43,10 @@ public class TestSmallDocumentBlock
_testdata[ j ] = ( byte ) j;
}
}
;
/**
* constructor
*
* @param name
*/
public TestSmallDocumentBlock(String name)
{
super(name);
}
/**
* Test conversion from DocumentBlocks
*
* @exception IOException
*/
public void testConvert1()
throws IOException
{
@ -113,12 +96,7 @@ public class TestSmallDocumentBlock
/**
* Test conversion from byte array
*
* @exception IOException;
*
* @exception IOException
*/
public void testConvert2()
throws IOException
{
@ -154,57 +132,9 @@ public class TestSmallDocumentBlock
}
}
/**
* 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
{
@ -294,17 +224,4 @@ public class TestSmallDocumentBlock
}
}
}
/**
* 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);
}
}

View File

@ -27,12 +27,11 @@ import junit.framework.TestSuite;
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);

View File

@ -1,50 +0,0 @@
/*
* 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
}
}
}

View File

@ -97,13 +97,13 @@ public final class TestLittleEndian extends TestCase {
* 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]);
}
@ -144,7 +144,7 @@ public final class TestLittleEndian extends TestCase {
(byte) 0x02,
};
assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata));
assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata, 0));
assertEquals(0x02FFFFFFFFFFFFFFL, LittleEndian.getLong(testdata, 1));
}
@ -194,7 +194,7 @@ public final class TestLittleEndian extends TestCase {
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 ];
@ -224,7 +224,7 @@ public final class TestLittleEndian extends TestCase {
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));

View File

@ -42,43 +42,7 @@ public class TestStringUtil
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
@ -101,62 +65,7 @@ public class TestStringUtil
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