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:
parent
2ccdeeaee6
commit
5965d73fd1
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,10 +15,8 @@
|
||||
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);
|
||||
}
|
||||
|
||||
final MutableTreeNode parentNode = getNode(d.path, filename, rootNode);
|
||||
final MutableTreeNode nameNode = new DefaultMutableTreeNode(d.name);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -51,7 +51,7 @@ public final class LinkedDataFormulaField {
|
||||
.append( "=" )
|
||||
.append(ptg.toString() )
|
||||
.append( "\n" )
|
||||
.append(ptg.toDebugString() )
|
||||
.append(ptg.toString())
|
||||
.append( "\n" );
|
||||
}
|
||||
}
|
||||
|
@ -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,57 +34,112 @@ 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;
|
||||
|
||||
private final byte[] data = new byte[MAX_RECORD_DATA_SIZE];
|
||||
private short recordOffset;
|
||||
private long pos;
|
||||
|
||||
private boolean autoContinue = true;
|
||||
/** {@link LittleEndianInput} facet of the wrapped {@link InputStream} */
|
||||
private final LittleEndianInput _le;
|
||||
/** the record identifier of the BIFF record currently being read */
|
||||
private int _currentSid;
|
||||
/**
|
||||
* Length of the data section of the current BIFF record (always 4 less than the total record size).
|
||||
* When uninitialised, this field is set to {@link #DATA_LEN_NEEDS_TO_BE_READ}.
|
||||
*/
|
||||
private int _currentDataLength;
|
||||
/**
|
||||
* The BIFF record identifier for the next record is read when just as the current record
|
||||
* is finished.
|
||||
* This field is only really valid during the time that ({@link #_currentDataLength} ==
|
||||
* {@link #DATA_LEN_NEEDS_TO_BE_READ}). At most other times its value is not really the
|
||||
* 'sid of the next record'. Wwhile mid-record, this field coincidentally holds the sid
|
||||
* of the current record.
|
||||
*/
|
||||
private int _nextSid;
|
||||
/**
|
||||
* index within the data section of the current BIFF record
|
||||
*/
|
||||
private int _currentDataOffset;
|
||||
|
||||
public RecordInputStream(InputStream in) throws RecordFormatException {
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
/** This method will read a byte from the current record*/
|
||||
public int read() {
|
||||
checkRecordPosition(LittleEndian.BYTE_SIZE);
|
||||
|
||||
byte result = data[recordOffset];
|
||||
recordOffset += LittleEndian.BYTE_SIZE;
|
||||
pos += LittleEndian.BYTE_SIZE;
|
||||
return result;
|
||||
_currentDataOffset += LittleEndian.BYTE_SIZE;
|
||||
return _le.readUByte();
|
||||
}
|
||||
public int read(byte[] b, int off, int len) {
|
||||
int limit = Math.min(len, remaining());
|
||||
if (limit == 0) {
|
||||
return 0;
|
||||
}
|
||||
readFully(b, off,limit);
|
||||
return limit;
|
||||
}
|
||||
|
||||
public short getSid() {
|
||||
return currentSid;
|
||||
}
|
||||
|
||||
public short getLength() {
|
||||
return currentLength;
|
||||
}
|
||||
|
||||
public short getRecordOffset() {
|
||||
return recordOffset;
|
||||
}
|
||||
|
||||
public long getPos() {
|
||||
return pos;
|
||||
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() {
|
||||
return nextSid != INVALID_SID_VALUE;
|
||||
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;
|
||||
}
|
||||
|
||||
/** Moves to the next record in the stream.
|
||||
@ -92,57 +147,34 @@ public final class RecordInputStream extends InputStream implements LittleEndian
|
||||
* <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));
|
||||
if (_nextSid == INVALID_SID_VALUE) {
|
||||
throw new IllegalStateException("EOF - next record not available");
|
||||
}
|
||||
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
|
||||
if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
|
||||
throw new IllegalStateException("Cannot call nextRecord() without checking hasNextRecord() first");
|
||||
}
|
||||
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());
|
||||
_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");
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RecordFormatException("Error reading bytes", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoContinue(boolean enable) {
|
||||
this.autoContinue = enable;
|
||||
}
|
||||
|
||||
public boolean getAutoContinue() {
|
||||
return autoContinue;
|
||||
}
|
||||
|
||||
private void checkRecordPosition(int requiredByteCount) {
|
||||
|
||||
if (remaining() < requiredByteCount) {
|
||||
if (isContinueNext() && autoContinue) {
|
||||
int nAvailable = remaining();
|
||||
if (nAvailable >= requiredByteCount) {
|
||||
// all OK
|
||||
return;
|
||||
}
|
||||
if (nAvailable == 0 && isContinueNext()) {
|
||||
nextRecord();
|
||||
} else {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
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() {
|
||||
@ -321,10 +336,11 @@ public final class RecordInputStream extends InputStream implements LittleEndian
|
||||
*/
|
||||
public byte[] readRemainder() {
|
||||
int size = remaining();
|
||||
if (size ==0) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
byte[] result = new byte[size];
|
||||
System.arraycopy(data, recordOffset, result, 0, size);
|
||||
recordOffset += size;
|
||||
pos += size;
|
||||
readFully(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -355,14 +371,29 @@ public final class RecordInputStream extends InputStream implements LittleEndian
|
||||
* @return The number of bytes remaining in the current record
|
||||
*/
|
||||
public int remaining() {
|
||||
return (currentLength - recordOffset);
|
||||
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.
|
||||
* @return <code>true</code> when a {@link ContinueRecord} is next.
|
||||
*/
|
||||
public boolean isContinueNext() {
|
||||
return (nextSid == ContinueRecord.sid);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -19,184 +19,77 @@ 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;
|
||||
|
||||
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;
|
||||
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 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)
|
||||
{
|
||||
public StyleRecord(RecordInputStream in) {
|
||||
field_1_xf_index = in.readShort();
|
||||
if (getType() == STYLE_BUILT_IN)
|
||||
{
|
||||
if (isBuiltin()) {
|
||||
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);
|
||||
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 entire index field (including the type) (see bit setters that reference this method)
|
||||
* @param index bitmask
|
||||
*/
|
||||
|
||||
public void setIndex(short index)
|
||||
{
|
||||
field_1_xf_index = index;
|
||||
}
|
||||
|
||||
// bitfields for field 1
|
||||
|
||||
/**
|
||||
* set the type of the style (builtin or user-defined)
|
||||
* @see #STYLE_USER_DEFINED
|
||||
* @see #STYLE_BUILT_IN
|
||||
* @param type of style (userdefined/builtin)
|
||||
* @see #setIndex(short)
|
||||
*/
|
||||
|
||||
public void setType(short type)
|
||||
{
|
||||
field_1_xf_index = setField(field_1_xf_index, type, 0x8000, 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the actual index of the style extended format record
|
||||
* @see #setIndex(short)
|
||||
* @param index of the xf record
|
||||
* @param xfIndex of the xf record
|
||||
*/
|
||||
|
||||
public void setXFIndex(short index)
|
||||
{
|
||||
field_1_xf_index = setField(field_1_xf_index, index, 0x1FFF, 0);
|
||||
}
|
||||
|
||||
// end bitfields
|
||||
// only for user defined records
|
||||
|
||||
/**
|
||||
* if this is a user defined record set the length of the style name
|
||||
* @param length of the style's name
|
||||
* @see #setName(String)
|
||||
*/
|
||||
|
||||
public void setNameLength(byte length)
|
||||
{
|
||||
field_2_name_length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the style's name
|
||||
* @param name of the style
|
||||
* @see #setNameLength(byte)
|
||||
*/
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
field_4_name = name;
|
||||
|
||||
// Fix up the length
|
||||
field_2_name_length = (short)name.length();
|
||||
//TODO set name string options
|
||||
}
|
||||
|
||||
// end user defined
|
||||
// only for buildin records
|
||||
|
||||
/**
|
||||
* if this is a builtin style set teh number of the built in style
|
||||
* @param builtin style number (0-7)
|
||||
*
|
||||
*/
|
||||
|
||||
public void setBuiltin(byte builtin)
|
||||
{
|
||||
field_2_builtin_style = builtin;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the row or column level of the style (if builtin 1||2)
|
||||
*/
|
||||
|
||||
public void setOutlineStyleLevel(byte level)
|
||||
{
|
||||
field_3_outline_style_level = level;
|
||||
}
|
||||
|
||||
// end builtin records
|
||||
// field 1
|
||||
|
||||
/**
|
||||
* get the entire index field (including the type) (see bit getters that reference this method)
|
||||
* @return bitmask
|
||||
*/
|
||||
|
||||
public short getIndex()
|
||||
{
|
||||
return field_1_xf_index;
|
||||
}
|
||||
|
||||
// bitfields for field 1
|
||||
|
||||
/**
|
||||
* get the type of the style (builtin or user-defined)
|
||||
* @see #STYLE_USER_DEFINED
|
||||
* @see #STYLE_BUILT_IN
|
||||
* @return type of style (userdefined/builtin)
|
||||
* @see #getIndex()
|
||||
*/
|
||||
|
||||
public short getType()
|
||||
{
|
||||
return ( short ) ((field_1_xf_index & 0x8000) >> 15);
|
||||
public void setXFIndex(int xfIndex) {
|
||||
field_1_xf_index = styleIndexMask.setValue(field_1_xf_index, xfIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,143 +97,99 @@ public final class StyleRecord extends Record {
|
||||
* @see #getIndex()
|
||||
* @return index of the xf record
|
||||
*/
|
||||
|
||||
public short getXFIndex()
|
||||
{
|
||||
return ( short ) (field_1_xf_index & 0x1FFF);
|
||||
public int getXFIndex() {
|
||||
return styleIndexMask.getValue(field_1_xf_index);
|
||||
}
|
||||
|
||||
// end bitfields
|
||||
// only for user defined records
|
||||
/**
|
||||
* set the style's name
|
||||
* @param name of the style
|
||||
*/
|
||||
public void setName(String name) {
|
||||
field_4_name = name;
|
||||
field_3_string_options = StringUtil.hasMultibyte(name) ? 0x01 : 0x00;
|
||||
field_1_xf_index = isBuiltinFlag.clear(field_1_xf_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* if this is a user defined record get the length of the style name
|
||||
* @return length of the style's name
|
||||
* @see #getName()
|
||||
* 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;
|
||||
}
|
||||
|
||||
public short getNameLength()
|
||||
{
|
||||
return field_2_name_length;
|
||||
/**
|
||||
* set the row or column level of the style (if builtin 1||2)
|
||||
*/
|
||||
public void setOutlineStyleLevel(int level) {
|
||||
field_3_outline_style_level = level & 0x00FF;
|
||||
}
|
||||
|
||||
public boolean isBuiltin(){
|
||||
return isBuiltinFlag.isSet(field_1_xf_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the style's name
|
||||
* @return name of the style
|
||||
* @see #getNameLength()
|
||||
*/
|
||||
|
||||
public String getName()
|
||||
{
|
||||
public String getName() {
|
||||
return field_4_name;
|
||||
}
|
||||
|
||||
// end user defined
|
||||
// only for buildin records
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the row or column level of the style (if builtin 1||2)
|
||||
*/
|
||||
|
||||
public byte getOutlineStyleLevel()
|
||||
{
|
||||
return field_3_outline_style_level;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
public int serialize(int offset, byte [] data) {
|
||||
int dataSize = getDataSize();
|
||||
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;
|
||||
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 getRecordSize();
|
||||
return 4+dataSize;
|
||||
}
|
||||
|
||||
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 int getRecordSize() {
|
||||
return 4 + getDataSize();
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
|
@ -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,12 +210,7 @@ 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();
|
||||
LittleEndianInput in = new LittleEndianByteArrayInputStream(formulaRawBytes);
|
||||
byte ptgSid = in.readByte();
|
||||
switch(ptgSid) {
|
||||
case AreaPtg.sid: return new AreaPtg(in);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
@ -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,34 +192,12 @@ 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);
|
||||
field_3_string = in.readCompressedUnicode(field_1_charCount);
|
||||
} else {
|
||||
char ch = (char) in.readShort();
|
||||
tmpString.append(ch);
|
||||
field_3_string = in.readUnicodeLEString(field_1_charCount);
|
||||
}
|
||||
stringCharCount --;
|
||||
}
|
||||
field_3_string = tmpString.toString();
|
||||
//Turn back on autocontinuation
|
||||
in.setAutoContinue(true);
|
||||
|
||||
|
||||
if (isRichText() && (runCount > 0)) {
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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))
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,110 +15,129 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Title: Write Access Record<P>
|
||||
* Description: Stores the username of that who owns the spreadsheet generator
|
||||
* (on unix the user's login, on Windoze its the name you typed when
|
||||
* you installed the thing)<P>
|
||||
* REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
||||
* Title: Write Access Record (0x005C)<p/>
|
||||
*
|
||||
* Description: Stores the username of that who owns the spreadsheet generator (on unix the user's
|
||||
* login, on Windoze its the name you typed when you installed the thing)
|
||||
* <p/>
|
||||
* REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
|
||||
* <p/>
|
||||
*
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class WriteAccessRecord
|
||||
extends Record
|
||||
{
|
||||
public final static short sid = 0x5c;
|
||||
public final class WriteAccessRecord extends Record {
|
||||
private static final byte PAD_CHAR = (byte) ' ';
|
||||
public final static short sid = 0x005C;
|
||||
private static final int DATA_SIZE = 112;
|
||||
private String field_1_username;
|
||||
/** this record is always padded to a constant length */
|
||||
private byte[] padding;
|
||||
|
||||
public WriteAccessRecord()
|
||||
{
|
||||
public WriteAccessRecord() {
|
||||
setUsername("");
|
||||
padding = new byte[DATA_SIZE - 3];
|
||||
}
|
||||
|
||||
public WriteAccessRecord(RecordInputStream in)
|
||||
{
|
||||
byte[] data = in.readRemainder();
|
||||
//The string is always 112 characters (padded with spaces), therefore
|
||||
//this record can not be continued.
|
||||
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.
|
||||
|
||||
//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);
|
||||
int nChars = in.readUShort();
|
||||
int is16BitFlag = in.readUByte();
|
||||
int expectedPadSize = DATA_SIZE - 3;
|
||||
if ((is16BitFlag & 0x01) == 0x00) {
|
||||
field_1_username = StringUtil.readCompressedUnicode(in, nChars);
|
||||
expectedPadSize -= nChars;
|
||||
} else {
|
||||
field_1_username = StringUtil.readUnicodeLE(in, nChars);
|
||||
expectedPadSize -= nChars * 2;
|
||||
}
|
||||
padding = new byte[expectedPadSize];
|
||||
int padSize = in.remaining();
|
||||
in.readFully(padding, 0, padSize);
|
||||
if (padSize < expectedPadSize) {
|
||||
// this occurs in a couple of test examples: "42564.xls",
|
||||
// "bug_42794.xls"
|
||||
Arrays.fill(padding, padSize, expectedPadSize, PAD_CHAR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the username for the user that created the report. HSSF uses the logged in user.
|
||||
* 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);
|
||||
|
||||
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.
|
||||
* 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()
|
||||
{
|
||||
public String getUsername() {
|
||||
return field_1_username;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[WRITEACCESS]\n");
|
||||
buffer.append(" .name = ")
|
||||
.append(field_1_username.toString()).append("\n");
|
||||
buffer.append(" .name = ").append(field_1_username.toString()).append("\n");
|
||||
buffer.append("[/WRITEACCESS]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data)
|
||||
{
|
||||
public int serialize(int offset, byte[] data) {
|
||||
String username = getUsername();
|
||||
StringBuffer temp = new StringBuffer(0x70 - (0x3));
|
||||
boolean is16bit = StringUtil.hasMultibyte(username);
|
||||
|
||||
temp.append(username);
|
||||
while (temp.length() < 0x70 - 0x3)
|
||||
{
|
||||
temp.append(
|
||||
" "); // (70 = fixed lenght -3 = the overhead bits of unicode string)
|
||||
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();
|
||||
}
|
||||
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();
|
||||
System.arraycopy(padding, 0, data, pos, padding.length);
|
||||
return 4 + DATA_SIZE;
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
return 116;
|
||||
public int getRecordSize() {
|
||||
return 4 + DATA_SIZE;
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
}
|
||||
|
@ -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() + "'");
|
||||
|
@ -98,7 +98,6 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
|
||||
buf.append(")");
|
||||
}
|
||||
|
||||
public abstract void writeBytes(byte[] array, int offset);
|
||||
public abstract int getSize();
|
||||
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
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
|
||||
@ -29,24 +29,30 @@ public abstract class Area2DPtgBase extends AreaPtgBase {
|
||||
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);
|
||||
}
|
||||
|
||||
public final int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public final String toFormulaString() {
|
||||
return formatReferenceAsString();
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getName());
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,21 +17,22 @@
|
||||
|
||||
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;
|
||||
public final static byte sid = 0x1D;
|
||||
private final boolean _value;
|
||||
|
||||
public BoolPtg(RecordInputStream in) {
|
||||
public BoolPtg(LittleEndianInput in) {
|
||||
_value = (in.readByte() == 1);
|
||||
}
|
||||
|
||||
@ -43,9 +44,9 @@ public final class BoolPtg extends ScalarConstantPtg {
|
||||
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() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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,17 +33,16 @@ 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()
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -17,12 +17,13 @@
|
||||
|
||||
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
|
||||
* 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)
|
||||
*/
|
||||
@ -33,23 +34,24 @@ public final class IntPtg extends ScalarConstantPtg {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
return i >= MIN_VALUE && i <= MAX_VALUE;
|
||||
}
|
||||
|
||||
public final static int SIZE = 3;
|
||||
public final static byte sid = 0x1e;
|
||||
private final int field_1_value;
|
||||
|
||||
public IntPtg(RecordInputStream in) {
|
||||
public IntPtg(LittleEndianInput in) {
|
||||
this(in.readUShort());
|
||||
}
|
||||
|
||||
public IntPtg(int value) {
|
||||
if(!isInRange(value)) {
|
||||
if (!isInRange(value)) {
|
||||
throw new IllegalArgumentException("value is out of range: " + value);
|
||||
}
|
||||
field_1_value = value;
|
||||
@ -59,9 +61,9 @@ public final class IntPtg extends ScalarConstantPtg {
|
||||
return field_1_value;
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset) {
|
||||
array[ offset + 0 ] = sid;
|
||||
LittleEndian.putUShort(array, offset + 1, getValue());
|
||||
public void write(LittleEndianOutput out) {
|
||||
out.writeByte(sid + getPtgClass());
|
||||
out.writeShort(getValue());
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula;
|
||||
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
|
||||
/**
|
||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
||||
@ -34,37 +35,28 @@ public final class IntersectionPtg extends OperationPtg {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
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()
|
||||
{
|
||||
public String toFormulaString() {
|
||||
return " ";
|
||||
}
|
||||
|
||||
|
||||
/** implementation of method from OperationsPtg*/
|
||||
public String toFormulaString(String[] operands)
|
||||
{
|
||||
public String toFormulaString(String[] operands) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append(operands[ 0 ]);
|
||||
buffer.append(operands[0]);
|
||||
buffer.append(" ");
|
||||
buffer.append(operands[ 1 ]);
|
||||
buffer.append(operands[1]);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int getNumberOfOperands()
|
||||
{
|
||||
public int getNumberOfOperands() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
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)
|
||||
@ -26,55 +26,32 @@ import org.apache.poi.util.LittleEndian;
|
||||
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;
|
||||
private final int field_1_reserved;
|
||||
private final int field_2_subex_len;
|
||||
|
||||
/** Creates new MemAreaPtg */
|
||||
|
||||
public MemAreaPtg()
|
||||
{
|
||||
public MemAreaPtg(int subexLen) {
|
||||
field_1_reserved = 0;
|
||||
field_2_subex_len = subexLen;
|
||||
}
|
||||
|
||||
public MemAreaPtg(RecordInputStream in)
|
||||
{
|
||||
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 void setSubexpressionLength(short subexlen)
|
||||
{
|
||||
field_2_subex_len = subexlen;
|
||||
}
|
||||
|
||||
public short getSubexpressionLength()
|
||||
{
|
||||
return field_2_subex_len;
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset)
|
||||
{
|
||||
array[offset] = (byte) (sid + getPtgClass());
|
||||
LittleEndian.putInt(array, offset + 1, field_1_reserved);
|
||||
LittleEndian.putShort(array, offset + 5, field_2_subex_len);
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
public int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public String toFormulaString()
|
||||
{
|
||||
public String toFormulaString() {
|
||||
return ""; // TODO: Not sure how to format this. -- DN
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -26,27 +26,32 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
||||
*/
|
||||
|
||||
public final class MemErrPtg extends MemAreaPtg {
|
||||
public final 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;
|
||||
|
||||
/** Creates new MemErrPtg */
|
||||
|
||||
public MemErrPtg()
|
||||
{
|
||||
public MemErrPtg(LittleEndianInput in) {
|
||||
field_1_reserved = in.readInt();
|
||||
field_2_subex_len = in.readShort();
|
||||
}
|
||||
|
||||
public MemErrPtg(RecordInputStream in) {
|
||||
super(in);
|
||||
public void write(LittleEndianOutput out) {
|
||||
out.writeByte(sid + getPtgClass());
|
||||
out.writeInt(field_1_reserved);
|
||||
out.writeShort(field_2_subex_len);
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset) {
|
||||
super.writeBytes(array, offset);
|
||||
array[offset] = (byte) (sid + getPtgClass());
|
||||
public int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public String toFormulaString()
|
||||
{
|
||||
public String toFormulaString() {
|
||||
return "ERR#";
|
||||
}
|
||||
|
||||
public byte getDefaultOperandClass() {
|
||||
return Ptg.CLASS_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
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)
|
||||
@ -28,10 +28,11 @@ public final class MemFuncPtg extends OperandPtg {
|
||||
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.
|
||||
/**
|
||||
* Creates new function pointer from a byte array usually called while
|
||||
* reading an excel file.
|
||||
*/
|
||||
public MemFuncPtg(RecordInputStream in) {
|
||||
public MemFuncPtg(LittleEndianInput in) {
|
||||
this(in.readUShort());
|
||||
}
|
||||
|
||||
@ -39,34 +40,28 @@ public final class MemFuncPtg extends OperandPtg {
|
||||
field_1_len_ref_subexpression = subExprLen;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
public int getSize() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public void writeBytes( byte[] array, int offset )
|
||||
{
|
||||
array[offset + 0] = sid ;
|
||||
LittleEndian.putUShort( array, offset + 1, field_1_len_ref_subexpression );
|
||||
public void write(LittleEndianOutput out) {
|
||||
out.writeByte(sid + getPtgClass());
|
||||
out.writeShort(field_1_len_ref_subexpression);
|
||||
}
|
||||
|
||||
public String toFormulaString()
|
||||
{
|
||||
public String toFormulaString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public byte getDefaultOperandClass()
|
||||
{
|
||||
public byte getDefaultOperandClass() {
|
||||
return Ptg.CLASS_REF;
|
||||
}
|
||||
|
||||
public int getNumberOfOperands()
|
||||
{
|
||||
public int getNumberOfOperands() {
|
||||
return field_1_len_ref_subexpression;
|
||||
}
|
||||
|
||||
public int getLenRefSubexpression()
|
||||
{
|
||||
public int getLenRefSubexpression() {
|
||||
return field_1_len_ref_subexpression;
|
||||
}
|
||||
}
|
@ -17,10 +17,13 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula;
|
||||
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
|
||||
/**
|
||||
* Missing Function Arguments
|
||||
*
|
||||
* Avik Sengupta <avik at apache.org>
|
||||
*
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
public final class MissingArgPtg extends ScalarConstantPtg {
|
||||
@ -34,8 +37,8 @@ public final class MissingArgPtg extends ScalarConstantPtg {
|
||||
// enforce singleton
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset) {
|
||||
array[ offset + 0 ] = sid;
|
||||
public void write(LittleEndianOutput out) {
|
||||
out.writeByte(sid + getPtgClass());
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -38,12 +38,12 @@ public final class NamePtg extends OperandPtg implements WorkbookDependentFormul
|
||||
* @param nameIndex zero-based index to name within workbook
|
||||
*/
|
||||
public NamePtg(int nameIndex) {
|
||||
field_1_label_index = 1+nameIndex; // convert to 1-based
|
||||
field_1_label_index = 1 + nameIndex; // convert to 1-based
|
||||
}
|
||||
|
||||
/** Creates new NamePtg */
|
||||
|
||||
public NamePtg(RecordInputStream in) {
|
||||
public NamePtg(LittleEndianInput in) {
|
||||
field_1_label_index = in.readShort();
|
||||
field_2_zero = in.readShort();
|
||||
}
|
||||
@ -52,23 +52,23 @@ public final class NamePtg extends OperandPtg implements WorkbookDependentFormul
|
||||
* @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
|
||||
return field_1_label_index - 1; // convert to zero based
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
public String toFormulaString(FormulaRenderingWorkbook book) {
|
||||
return book.getNameText(this);
|
||||
}
|
||||
|
||||
public String toFormulaString() {
|
||||
throw new RuntimeException("3D references need a workbook to determine formula text");
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -17,13 +17,13 @@
|
||||
|
||||
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
|
||||
* 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)
|
||||
*/
|
||||
@ -32,15 +32,16 @@ public final class NumberPtg extends ScalarConstantPtg {
|
||||
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) {
|
||||
public NumberPtg(LittleEndianInput 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
|
||||
/**
|
||||
* 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));
|
||||
@ -54,9 +55,9 @@ public final class NumberPtg extends ScalarConstantPtg {
|
||||
return field_1_value;
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset) {
|
||||
array[ offset + 0 ] = sid;
|
||||
LittleEndian.putDouble(array, offset + 1, getValue());
|
||||
public void write(LittleEndianOutput out) {
|
||||
out.writeByte(sid + getPtgClass());
|
||||
out.writeDouble(getValue());
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
@ -65,7 +66,6 @@ public final class NumberPtg extends ScalarConstantPtg {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -15,17 +15,18 @@
|
||||
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
|
||||
* While formula tokens are stored in RPN order and thus do not need parenthesis
|
||||
* for precedence reasons, Parenthesis tokens ARE written to ensure that user
|
||||
* entered parenthesis are displayed as-is on reading back
|
||||
*
|
||||
* Avik Sengupta <lists@aviksengupta.com> Andrew C. Oliver (acoliver at
|
||||
* apache dot org)
|
||||
*
|
||||
* Avik Sengupta <lists@aviksengupta.com>
|
||||
* Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
public final class ParenthesisPtg extends ControlPtg {
|
||||
@ -34,27 +35,24 @@ public final class ParenthesisPtg extends ControlPtg {
|
||||
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 void write(LittleEndianOutput out) {
|
||||
out.writeByte(sid + getPtgClass());
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
public int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public String toFormulaString()
|
||||
{
|
||||
public String toFormulaString() {
|
||||
return "()";
|
||||
}
|
||||
|
||||
|
||||
public String toFormulaString(String[] operands) {
|
||||
return "("+operands[0]+")";
|
||||
return "(" + operands[0] + ")";
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
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
|
||||
@ -41,21 +41,25 @@ abstract class Ref2DPtgBase extends RefPtgBase {
|
||||
setColRelative(isColumnRelative);
|
||||
}
|
||||
|
||||
protected Ref2DPtgBase(RecordInputStream in) {
|
||||
protected Ref2DPtgBase(LittleEndianInput in) {
|
||||
readCoordinates(in);
|
||||
}
|
||||
public final void writeBytes(byte [] array, int offset) {
|
||||
LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
|
||||
writeCoordinates(array, offset+1);
|
||||
|
||||
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());
|
||||
|
@ -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() {
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -17,14 +17,15 @@
|
||||
|
||||
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 Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
@ -34,10 +35,9 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
|
||||
/** 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
|
||||
/**
|
||||
* 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);
|
||||
@ -45,7 +45,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
private static final BitField column = BitFieldFactory.getInstance(0x00FF);
|
||||
|
||||
protected RefPtgBase() {
|
||||
//Required for clone methods
|
||||
// Required for clone methods
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,7 +53,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
* numeric fields.
|
||||
*/
|
||||
protected RefPtgBase(String cellref) {
|
||||
CellReference c= new CellReference(cellref);
|
||||
CellReference c = new CellReference(cellref);
|
||||
setRow(c.getRow());
|
||||
setColumn(c.getCol());
|
||||
setColRelative(!c.isColAbsolute());
|
||||
@ -67,26 +67,27 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
setColRelative(isColumnRelative);
|
||||
}
|
||||
|
||||
protected final void readCoordinates(RecordInputStream in) {
|
||||
protected final void readCoordinates(LittleEndianInput 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 writeCoordinates(LittleEndianOutput out) {
|
||||
out.writeShort(field_1_row);
|
||||
out.writeShort(field_2_col);
|
||||
}
|
||||
|
||||
public final void setRow(int row) {
|
||||
if(row < 0 || row >= MAX_ROW_NUMBER) {
|
||||
throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + MAX_ROW_NUMBER);
|
||||
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 = row;
|
||||
field_1_row = rowIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the row number as an int, between 0 and 65535
|
||||
*/
|
||||
public final int getRow(){
|
||||
public final int getRow() {
|
||||
return field_1_row;
|
||||
}
|
||||
|
||||
@ -95,7 +96,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
}
|
||||
|
||||
public final void setRowRelative(boolean rel) {
|
||||
field_2_col=rowRelative.setBoolean(field_2_col,rel);
|
||||
field_2_col = rowRelative.setBoolean(field_2_col, rel);
|
||||
}
|
||||
|
||||
public final boolean isColRelative() {
|
||||
@ -103,11 +104,11 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
}
|
||||
|
||||
public final void setColRelative(boolean rel) {
|
||||
field_2_col=colRelative.setBoolean(field_2_col,rel);
|
||||
field_2_col = colRelative.setBoolean(field_2_col, rel);
|
||||
}
|
||||
|
||||
public final void setColumn(int col) {
|
||||
if(col < 0 || col >= 0x100) {
|
||||
if (col < 0 || col >= 0x100) {
|
||||
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
|
||||
}
|
||||
field_2_col = column.setValue(field_2_col, col);
|
||||
@ -116,6 +117,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
||||
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());
|
||||
|
@ -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,28 +30,25 @@ 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 */
|
||||
/** 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);
|
||||
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 = in.readCompressedUnicode(field_1_length);
|
||||
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() {
|
||||
|
@ -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() {
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -17,11 +17,12 @@
|
||||
|
||||
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
|
||||
*/
|
||||
@ -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,6 +48,7 @@ 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");
|
||||
|
@ -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);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,436 +15,313 @@
|
||||
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
|
||||
/** current offset into the Document */
|
||||
private int _current_offset;
|
||||
|
||||
// current marked offset into the Document (used by mark and
|
||||
// reset)
|
||||
/** current marked offset into the Document (used by mark and reset) */
|
||||
private int _marked_offset;
|
||||
|
||||
// the Document's size
|
||||
/** the Document's size */
|
||||
private int _document_size;
|
||||
|
||||
// have we been closed?
|
||||
/** have we been closed? */
|
||||
private boolean _closed;
|
||||
|
||||
// the actual Document
|
||||
/** the actual Document */
|
||||
private POIFSDocument _document;
|
||||
|
||||
// buffer used to read one byte at a time
|
||||
private byte[] _tiny_buffer;
|
||||
|
||||
// returned by read operations if we're at end of document
|
||||
static private final int EOD = -1;
|
||||
/** the data block containing the current stream pointer */
|
||||
private DataInputBlock _currentBlock;
|
||||
|
||||
/**
|
||||
* Create an InputStream from the specified DocumentEntry
|
||||
*
|
||||
* @param document the DocumentEntry to be read
|
||||
*
|
||||
* @exception IOException if the DocumentEntry cannot be opened
|
||||
* (like, maybe it has been deleted?)
|
||||
* @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
|
||||
* been deleted?)
|
||||
*/
|
||||
|
||||
public DocumentInputStream(final DocumentEntry document)
|
||||
throws IOException
|
||||
{
|
||||
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;
|
||||
_tiny_buffer = null;
|
||||
if (document instanceof DocumentNode)
|
||||
{
|
||||
_document = (( DocumentNode ) document).getDocument();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("Cannot open internal document storage");
|
||||
}
|
||||
_document = ((DocumentNode) document).getDocument();
|
||||
_currentBlock = getDataInputBlock(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an InputStream from the specified Document
|
||||
*
|
||||
* @param document the Document to be read
|
||||
*
|
||||
* @exception IOException if the DocumentEntry cannot be opened
|
||||
* (like, maybe it has been deleted?)
|
||||
*/
|
||||
|
||||
public DocumentInputStream(final POIFSDocument document)
|
||||
throws IOException
|
||||
{
|
||||
public DocumentInputStream(POIFSDocument document) {
|
||||
_current_offset = 0;
|
||||
_marked_offset = 0;
|
||||
_document_size = document.getSize();
|
||||
_closed = false;
|
||||
_tiny_buffer = null;
|
||||
_document = document;
|
||||
_currentBlock = getDataInputBlock(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read (or skipped over)
|
||||
* from this input stream without blocking by the next caller of a
|
||||
* method for this input stream. The next caller might be the same
|
||||
* thread or or another thread.
|
||||
*
|
||||
* @return the number of bytes that can be read from this input
|
||||
* stream without blocking.
|
||||
*
|
||||
* @exception IOException on error (such as the stream has been
|
||||
* closed)
|
||||
*/
|
||||
|
||||
public int available()
|
||||
throws IOException
|
||||
{
|
||||
dieIfClosed();
|
||||
public int available() {
|
||||
if (_closed) {
|
||||
throw new IllegalStateException("cannot perform requested operation on a closed stream");
|
||||
}
|
||||
return _document_size - _current_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources
|
||||
* associated with the stream.
|
||||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
|
||||
public void close()
|
||||
throws IOException
|
||||
{
|
||||
public void close() {
|
||||
_closed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current position in this input stream. A subsequent
|
||||
* call to the reset method repositions this stream at the last
|
||||
* marked position so that subsequent reads re-read the same
|
||||
* bytes.
|
||||
* <p>
|
||||
* The readlimit arguments tells this input stream to allow that
|
||||
* many bytes to be read before the mark position gets
|
||||
* invalidated. This implementation, however, does not care.
|
||||
* <p>
|
||||
* The general contract of mark is that, if the method
|
||||
* markSupported returns true, the stream somehow remembers all
|
||||
* the bytes read after the call to mark and stands ready to
|
||||
* supply those same bytes again if and whenever the method reset
|
||||
* is called. However, the stream is not required to remember any
|
||||
* data at all if more than readlimit bytes are read from the
|
||||
* stream before reset is called. But this stream will.
|
||||
*
|
||||
* @param ignoredReadlimit the maximum limit of bytes that can be
|
||||
* read before the mark position becomes
|
||||
* invalid. Ignored by this
|
||||
* implementation.
|
||||
*/
|
||||
|
||||
public void mark(int ignoredReadlimit)
|
||||
{
|
||||
public void mark(int ignoredReadlimit) {
|
||||
_marked_offset = _current_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if this input stream supports the mark and reset methods.
|
||||
*
|
||||
* @return true
|
||||
* @return <code>true</code> always
|
||||
*/
|
||||
|
||||
public boolean markSupported()
|
||||
{
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from the input stream. The value
|
||||
* byte is returned as an int in the range 0 to 255. If no byte is
|
||||
* available because the end of the stream has been reached, the
|
||||
* value -1 is returned. The definition of this method in
|
||||
* java.io.InputStream allows this method to block, but it won't.
|
||||
*
|
||||
* @return the next byte of data, or -1 if the end of the stream
|
||||
* is reached.
|
||||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
private DataInputBlock getDataInputBlock(int offset) {
|
||||
return _document.getDataInputBlock(offset);
|
||||
}
|
||||
|
||||
public int read()
|
||||
throws IOException
|
||||
{
|
||||
public int read() throws IOException {
|
||||
dieIfClosed();
|
||||
if (atEOD())
|
||||
{
|
||||
return EOD;
|
||||
if (atEOD()) {
|
||||
return EOF;
|
||||
}
|
||||
if (_tiny_buffer == null)
|
||||
{
|
||||
_tiny_buffer = new byte[ 1 ];
|
||||
int result = _currentBlock.readUByte();
|
||||
_current_offset++;
|
||||
if (_currentBlock.available() < 1) {
|
||||
_currentBlock = getDataInputBlock(_current_offset);
|
||||
}
|
||||
_document.read(_tiny_buffer, _current_offset++);
|
||||
return ((int)_tiny_buffer[ 0 ]) & 0x000000FF;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads some number of bytes from the input stream and stores
|
||||
* them into the buffer array b. The number of bytes actually read
|
||||
* is returned as an integer. The definition of this method in
|
||||
* java.io.InputStream allows this method to block, but it won't.
|
||||
* <p>
|
||||
* If b is null, a NullPointerException is thrown. If the length
|
||||
* of b is zero, then no bytes are read and 0 is returned;
|
||||
* otherwise, there is an attempt to read at least one byte. If no
|
||||
* byte is available because the stream is at end of file, the
|
||||
* value -1 is returned; otherwise, at least one byte is read and
|
||||
* stored into b.
|
||||
* <p>
|
||||
* The first byte read is stored into element b[0], the next one
|
||||
* into b[1], and so on. The number of bytes read is, at most,
|
||||
* equal to the length of b. Let k be the number of bytes actually
|
||||
* read; these bytes will be stored in elements b[0] through
|
||||
* b[k-1], leaving elements b[k] through b[b.length-1] unaffected.
|
||||
* <p>
|
||||
* If the first byte cannot be read for any reason other than end
|
||||
* of file, then an IOException is thrown. In particular, an
|
||||
* IOException is thrown if the input stream has been closed.
|
||||
* <p>
|
||||
* The read(b) method for class InputStream has the same effect as:
|
||||
* <p>
|
||||
* <code>read(b, 0, b.length)</code>
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
*
|
||||
* @return the total number of bytes read into the buffer, or -1
|
||||
* if there is no more data because the end of the stream
|
||||
* has been reached.
|
||||
*
|
||||
* @exception IOException
|
||||
* @exception NullPointerException
|
||||
*/
|
||||
|
||||
public int read(final byte [] b)
|
||||
throws IOException, NullPointerException
|
||||
{
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from the input stream into an
|
||||
* array of bytes. An attempt is made to read as many as len
|
||||
* bytes, but a smaller number may be read, possibly zero. The
|
||||
* number of bytes actually read is returned as an integer.
|
||||
* <p>
|
||||
* The definition of this method in java.io.InputStream allows it
|
||||
* to block, but it won't.
|
||||
* <p>
|
||||
* If b is null, a NullPointerException is thrown.
|
||||
* <p>
|
||||
* If off is negative, or len is negative, or off+len is greater
|
||||
* than the length of the array b, then an
|
||||
* IndexOutOfBoundsException is thrown.
|
||||
* <p>
|
||||
* If len is zero, then no bytes are read and 0 is returned;
|
||||
* otherwise, there is an attempt to read at least one byte. If no
|
||||
* byte is available because the stream is at end of file, the
|
||||
* value -1 is returned; otherwise, at least one byte is read and
|
||||
* stored into b.
|
||||
* <p>
|
||||
* The first byte read is stored into element b[off], the next one
|
||||
* into b[off+1], and so on. The number of bytes read is, at most,
|
||||
* equal to len. Let k be the number of bytes actually read; these
|
||||
* bytes will be stored in elements b[off] through b[off+k-1],
|
||||
* leaving elements b[off+k] through b[off+len-1] unaffected.
|
||||
* <p>
|
||||
* In every case, elements b[0] through b[off] and elements
|
||||
* b[off+len] through b[b.length-1] are unaffected.
|
||||
* <p>
|
||||
* If the first byte cannot be read for any reason other than end
|
||||
* of file, then an IOException is thrown. In particular, an
|
||||
* IOException is thrown if the input stream has been closed.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @param off the start offset in array b at which the data is
|
||||
* written.
|
||||
* @param len the maximum number of bytes to read.
|
||||
*
|
||||
* @return the total number of bytes read into the buffer, or -1
|
||||
* if there is no more data because the end of the stream
|
||||
* has been reached.
|
||||
*
|
||||
* @exception IOException
|
||||
* @exception NullPointerException
|
||||
* @exception IndexOutOfBoundsException
|
||||
*/
|
||||
|
||||
public int read(final byte [] b, final int off, final int len)
|
||||
throws IOException, NullPointerException, IndexOutOfBoundsException
|
||||
{
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
dieIfClosed();
|
||||
if (b == null)
|
||||
{
|
||||
throw new NullPointerException("buffer is null");
|
||||
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 (off < 0 || len < 0 || b.length < off + len) {
|
||||
throw new IndexOutOfBoundsException("can't read past buffer boundaries");
|
||||
}
|
||||
if (len == 0)
|
||||
{
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (atEOD())
|
||||
{
|
||||
return EOD;
|
||||
if (atEOD()) {
|
||||
return EOF;
|
||||
}
|
||||
int limit = Math.min(available(), len);
|
||||
|
||||
if ((off == 0) && (limit == b.length))
|
||||
{
|
||||
_document.read(b, _current_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] buffer = new byte[ limit ];
|
||||
|
||||
_document.read(buffer, _current_offset);
|
||||
System.arraycopy(buffer, 0, b, off, limit);
|
||||
}
|
||||
_current_offset += limit;
|
||||
readFully(b, off, limit);
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repositions this stream to the position at the time the mark
|
||||
* method was last called on this input stream.
|
||||
* <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.
|
||||
* 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()
|
||||
{
|
||||
public void reset() {
|
||||
_current_offset = _marked_offset;
|
||||
_currentBlock = getDataInputBlock(_current_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over and discards n bytes of data from this input
|
||||
* stream. The skip method may, for a variety of reasons, end up
|
||||
* skipping over some smaller number of bytes, possibly 0. This
|
||||
* may result from any of a number of conditions; reaching end of
|
||||
* file before n bytes have been skipped is only one
|
||||
* possibility. The actual number of bytes skipped is returned. If
|
||||
* n is negative, no bytes are skipped.
|
||||
*
|
||||
* @param n the number of bytes to be skipped.
|
||||
*
|
||||
* @return the actual number of bytes skipped.
|
||||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
|
||||
public long skip(final long n)
|
||||
throws IOException
|
||||
{
|
||||
public long skip(long n) throws IOException {
|
||||
dieIfClosed();
|
||||
if (n < 0)
|
||||
{
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
int new_offset = _current_offset + ( int ) n;
|
||||
int new_offset = _current_offset + (int) n;
|
||||
|
||||
if (new_offset < _current_offset)
|
||||
{
|
||||
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)
|
||||
{
|
||||
} else if (new_offset > _document_size) {
|
||||
new_offset = _document_size;
|
||||
}
|
||||
long rval = new_offset - _current_offset;
|
||||
|
||||
_current_offset = new_offset;
|
||||
_currentBlock = getDataInputBlock(_current_offset);
|
||||
return rval;
|
||||
}
|
||||
|
||||
private void dieIfClosed()
|
||||
throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
{
|
||||
throw new IOException(
|
||||
"cannot perform requested operation on a closed stream");
|
||||
private void dieIfClosed() throws IOException {
|
||||
if (_closed) {
|
||||
throw new IOException("cannot perform requested operation on a closed stream");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean atEOD()
|
||||
{
|
||||
private boolean atEOD() {
|
||||
return _current_offset == _document_size;
|
||||
}
|
||||
} // end public class DocumentInputStream
|
||||
|
||||
private void checkAvaliable(int requestedSize) {
|
||||
if (_closed) {
|
||||
throw new IllegalStateException("cannot perform requested operation on a closed stream");
|
||||
}
|
||||
if (requestedSize > _document_size - _current_offset) {
|
||||
throw new RuntimeException("Buffer underrun - requested " + requestedSize
|
||||
+ " bytes but " + (_document_size - _current_offset) + " was available");
|
||||
}
|
||||
}
|
||||
|
||||
public byte readByte() {
|
||||
return (byte) readUByte();
|
||||
}
|
||||
|
||||
public double readDouble() {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
public void readFully(byte[] buf) {
|
||||
readFully(buf, 0, buf.length);
|
||||
}
|
||||
|
||||
public short readShort() {
|
||||
return (short) readUShort();
|
||||
}
|
||||
|
||||
public void readFully(byte[] buf, int off, int len) {
|
||||
checkAvaliable(len);
|
||||
int blockAvailable = _currentBlock.available();
|
||||
if (blockAvailable > len) {
|
||||
_currentBlock.readFully(buf, off, len);
|
||||
_current_offset += len;
|
||||
return;
|
||||
}
|
||||
// else read big amount in chunks
|
||||
int remaining = len;
|
||||
int writePos = off;
|
||||
while (remaining > 0) {
|
||||
boolean blockIsExpiring = remaining >= blockAvailable;
|
||||
int reqSize;
|
||||
if (blockIsExpiring) {
|
||||
reqSize = blockAvailable;
|
||||
} else {
|
||||
reqSize = remaining;
|
||||
}
|
||||
_currentBlock.readFully(buf, writePos, reqSize);
|
||||
remaining -= reqSize;
|
||||
writePos += reqSize;
|
||||
_current_offset += reqSize;
|
||||
if (blockIsExpiring) {
|
||||
if (_current_offset == _document_size) {
|
||||
if (remaining > 0) {
|
||||
throw new IllegalStateException(
|
||||
"reached end of document stream unexpectedly");
|
||||
}
|
||||
_currentBlock = null;
|
||||
break;
|
||||
}
|
||||
_currentBlock = getDataInputBlock(_current_offset);
|
||||
blockAvailable = _currentBlock.available();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long readLong() {
|
||||
checkAvaliable(SIZE_LONG);
|
||||
int blockAvailable = _currentBlock.available();
|
||||
long result;
|
||||
if (blockAvailable > SIZE_LONG) {
|
||||
result = _currentBlock.readLongLE();
|
||||
} else {
|
||||
DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
|
||||
if (blockAvailable == SIZE_LONG) {
|
||||
result = _currentBlock.readLongLE();
|
||||
} else {
|
||||
result = nextBlock.readLongLE(_currentBlock, blockAvailable);
|
||||
}
|
||||
_currentBlock = nextBlock;
|
||||
}
|
||||
_current_offset += SIZE_LONG;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readInt() {
|
||||
checkAvaliable(SIZE_INT);
|
||||
int blockAvailable = _currentBlock.available();
|
||||
int result;
|
||||
if (blockAvailable > SIZE_INT) {
|
||||
result = _currentBlock.readIntLE();
|
||||
} else {
|
||||
DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
|
||||
if (blockAvailable == SIZE_INT) {
|
||||
result = _currentBlock.readIntLE();
|
||||
} else {
|
||||
result = nextBlock.readIntLE(_currentBlock, blockAvailable);
|
||||
}
|
||||
_currentBlock = nextBlock;
|
||||
}
|
||||
_current_offset += SIZE_INT;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readUShort() {
|
||||
checkAvaliable(SIZE_SHORT);
|
||||
int blockAvailable = _currentBlock.available();
|
||||
int result;
|
||||
if (blockAvailable > SIZE_SHORT) {
|
||||
result = _currentBlock.readUShortLE();
|
||||
} else {
|
||||
DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
|
||||
if (blockAvailable == SIZE_SHORT) {
|
||||
result = _currentBlock.readUShortLE();
|
||||
} else {
|
||||
result = nextBlock.readUShortLE(_currentBlock);
|
||||
}
|
||||
_currentBlock = nextBlock;
|
||||
}
|
||||
_current_offset += SIZE_SHORT;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readUByte() {
|
||||
checkAvaliable(1);
|
||||
int result = _currentBlock.readUByte();
|
||||
_current_offset++;
|
||||
if (_currentBlock.available() < 1) {
|
||||
_currentBlock = getDataInputBlock(_current_offset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,20 +15,25 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.poifs.filesystem;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.poifs.common.POIFSConstants;
|
||||
import org.apache.poi.poifs.dev.POIFSViewable;
|
||||
import org.apache.poi.poifs.property.DocumentProperty;
|
||||
import org.apache.poi.poifs.property.Property;
|
||||
import org.apache.poi.poifs.storage.BlockWritable;
|
||||
import org.apache.poi.poifs.storage.ListManagedBlock;
|
||||
import org.apache.poi.poifs.storage.DataInputBlock;
|
||||
import org.apache.poi.poifs.storage.DocumentBlock;
|
||||
import org.apache.poi.poifs.storage.ListManagedBlock;
|
||||
import org.apache.poi.poifs.storage.RawDataBlock;
|
||||
import org.apache.poi.poifs.storage.SmallDocumentBlock;
|
||||
import org.apache.poi.util.HexDump;
|
||||
@ -39,10 +43,9 @@ import org.apache.poi.util.HexDump;
|
||||
*
|
||||
* @author Marc Johnson (mjohnson at apache dot org)
|
||||
*/
|
||||
|
||||
public class POIFSDocument
|
||||
implements BATManaged, BlockWritable, POIFSViewable
|
||||
{
|
||||
public final class POIFSDocument implements BATManaged, BlockWritable, POIFSViewable {
|
||||
private static final DocumentBlock[] EMPTY_BIG_BLOCK_ARRAY = { };
|
||||
private static final SmallDocumentBlock[] EMPTY_SMALL_BLOCK_ARRAY = { };
|
||||
private DocumentProperty _property;
|
||||
private int _size;
|
||||
|
||||
@ -56,21 +59,32 @@ public class POIFSDocument
|
||||
* @param name the name of the POIFSDocument
|
||||
* @param blocks the big blocks making up the POIFSDocument
|
||||
* @param length the actual length of the POIFSDocument
|
||||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
|
||||
public POIFSDocument(final String name, final RawDataBlock [] blocks,
|
||||
final int length)
|
||||
throws IOException
|
||||
{
|
||||
public POIFSDocument(String name, RawDataBlock[] blocks, int length) throws IOException {
|
||||
_size = length;
|
||||
_big_store = new BigBlockStore(blocks);
|
||||
_big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
|
||||
_property = new DocumentProperty(name, _size);
|
||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
||||
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||
_property.setDocument(this);
|
||||
}
|
||||
|
||||
// TODO - awkward typing going on here
|
||||
private static DocumentBlock[] convertRawBlocksToBigBlocks(ListManagedBlock[] blocks) throws IOException {
|
||||
DocumentBlock[] result = new DocumentBlock[blocks.length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = new DocumentBlock((RawDataBlock)blocks[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private static SmallDocumentBlock[] convertRawBlocksToSmallBlocks(ListManagedBlock[] blocks) {
|
||||
if (blocks instanceof SmallDocumentBlock[]) {
|
||||
return (SmallDocumentBlock[]) blocks;
|
||||
}
|
||||
SmallDocumentBlock[] result = new SmallDocumentBlock[blocks.length];
|
||||
System.arraycopy(blocks, 0, result, 0, blocks.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from small blocks
|
||||
*
|
||||
@ -78,20 +92,9 @@ public class POIFSDocument
|
||||
* @param blocks the small blocks making up the POIFSDocument
|
||||
* @param length the actual length of the POIFSDocument
|
||||
*/
|
||||
|
||||
public POIFSDocument(final String name,
|
||||
final SmallDocumentBlock [] blocks, final int length)
|
||||
{
|
||||
public POIFSDocument(String name, SmallDocumentBlock[] blocks, int length) {
|
||||
_size = length;
|
||||
try
|
||||
{
|
||||
_big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
|
||||
}
|
||||
catch (IOException ignored)
|
||||
{
|
||||
|
||||
// can't happen with that constructor
|
||||
}
|
||||
_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
|
||||
_property = new DocumentProperty(name, _size);
|
||||
_small_store = new SmallBlockStore(blocks);
|
||||
_property.setDocument(this);
|
||||
@ -103,26 +106,17 @@ public class POIFSDocument
|
||||
* @param name the name of the POIFSDocument
|
||||
* @param blocks the small blocks making up the POIFSDocument
|
||||
* @param length the actual length of the POIFSDocument
|
||||
*
|
||||
* @exception IOException
|
||||
*/
|
||||
|
||||
public POIFSDocument(final String name, final ListManagedBlock [] blocks,
|
||||
final int length)
|
||||
throws IOException
|
||||
{
|
||||
public POIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
|
||||
_size = length;
|
||||
_property = new DocumentProperty(name, _size);
|
||||
_property.setDocument(this);
|
||||
if (Property.isSmall(_size))
|
||||
{
|
||||
_big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
|
||||
_small_store = new SmallBlockStore(blocks);
|
||||
}
|
||||
else
|
||||
{
|
||||
_big_store = new BigBlockStore(blocks);
|
||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
||||
if (Property.isSmall(_size)) {
|
||||
_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
|
||||
_small_store = new SmallBlockStore(convertRawBlocksToSmallBlocks(blocks));
|
||||
} else {
|
||||
_big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
|
||||
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,47 +125,33 @@ public class POIFSDocument
|
||||
*
|
||||
* @param name the name of the POIFSDocument
|
||||
* @param stream the InputStream we read data from
|
||||
*
|
||||
* @exception IOException thrown on read errors
|
||||
*/
|
||||
|
||||
public POIFSDocument(final String name, final InputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
public POIFSDocument(String name, InputStream stream) throws IOException {
|
||||
List blocks = new ArrayList();
|
||||
|
||||
_size = 0;
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
DocumentBlock block = new DocumentBlock(stream);
|
||||
int blockSize = block.size();
|
||||
|
||||
if (blockSize > 0)
|
||||
{
|
||||
if (blockSize > 0) {
|
||||
blocks.add(block);
|
||||
_size += blockSize;
|
||||
}
|
||||
if (block.partiallyRead())
|
||||
{
|
||||
if (block.partiallyRead()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
DocumentBlock[] bigBlocks =
|
||||
( DocumentBlock [] ) blocks.toArray(new DocumentBlock[ 0 ]);
|
||||
DocumentBlock[] bigBlocks = (DocumentBlock[]) blocks.toArray(new DocumentBlock[blocks.size()]);
|
||||
|
||||
_big_store = new BigBlockStore(bigBlocks);
|
||||
_property = new DocumentProperty(name, _size);
|
||||
_property.setDocument(this);
|
||||
if (_property.shouldUseSmallBlocks())
|
||||
{
|
||||
_small_store =
|
||||
new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks,
|
||||
_size));
|
||||
_big_store = new BigBlockStore(new DocumentBlock[ 0 ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
||||
if (_property.shouldUseSmallBlocks()) {
|
||||
_small_store = new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks, _size));
|
||||
_big_store = new BigBlockStore(new DocumentBlock[0]);
|
||||
} else {
|
||||
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,49 +161,32 @@ public class POIFSDocument
|
||||
* @param name the name of the POIFSDocument
|
||||
* @param size the length of the POIFSDocument
|
||||
* @param path the path of the POIFSDocument
|
||||
* @param writer the writer who will eventually write the document
|
||||
* contents
|
||||
*
|
||||
* @exception IOException thrown on read errors
|
||||
* @param writer the writer who will eventually write the document contents
|
||||
*/
|
||||
|
||||
public POIFSDocument(final String name, final int size,
|
||||
final POIFSDocumentPath path,
|
||||
final POIFSWriterListener writer)
|
||||
throws IOException
|
||||
{
|
||||
public POIFSDocument(String name, int size, POIFSDocumentPath path, POIFSWriterListener writer) {
|
||||
_size = size;
|
||||
_property = new DocumentProperty(name, _size);
|
||||
_property.setDocument(this);
|
||||
if (_property.shouldUseSmallBlocks())
|
||||
{
|
||||
if (_property.shouldUseSmallBlocks()) {
|
||||
_small_store = new SmallBlockStore(path, name, size, writer);
|
||||
_big_store = new BigBlockStore(new Object[ 0 ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
||||
_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
|
||||
} else {
|
||||
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||
_big_store = new BigBlockStore(path, name, size, writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the array of SmallDocumentBlocks used
|
||||
*
|
||||
* @return array of SmallDocumentBlocks; may be empty, cannot be null
|
||||
*/
|
||||
|
||||
public BlockWritable [] getSmallBlocks()
|
||||
{
|
||||
public BlockWritable[] getSmallBlocks() {
|
||||
return _small_store.getBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return size of the document
|
||||
*/
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
public int getSize() {
|
||||
return _size;
|
||||
}
|
||||
|
||||
@ -232,28 +195,70 @@ public class POIFSDocument
|
||||
*
|
||||
* @param buffer the buffer to write to
|
||||
* @param offset the offset into our storage to read from
|
||||
* This method is currently (Oct 2008) only used by test code. Perhaps it can be deleted
|
||||
*/
|
||||
void read(byte[] buffer, int offset) {
|
||||
int len = buffer.length;
|
||||
|
||||
void read(final byte [] buffer, final int offset)
|
||||
{
|
||||
if (_property.shouldUseSmallBlocks())
|
||||
{
|
||||
SmallDocumentBlock.read(_small_store.getBlocks(), buffer, offset);
|
||||
DataInputBlock currentBlock = getDataInputBlock(offset);
|
||||
|
||||
int blockAvailable = currentBlock.available();
|
||||
if (blockAvailable > len) {
|
||||
currentBlock.readFully(buffer, 0, len);
|
||||
return;
|
||||
}
|
||||
// else read big amount in chunks
|
||||
int remaining = len;
|
||||
int writePos = 0;
|
||||
int currentOffset = offset;
|
||||
while (remaining > 0) {
|
||||
boolean blockIsExpiring = remaining >= blockAvailable;
|
||||
int reqSize;
|
||||
if (blockIsExpiring) {
|
||||
reqSize = blockAvailable;
|
||||
} else {
|
||||
reqSize = remaining;
|
||||
}
|
||||
currentBlock.readFully(buffer, writePos, reqSize);
|
||||
remaining-=reqSize;
|
||||
writePos+=reqSize;
|
||||
currentOffset += reqSize;
|
||||
if (blockIsExpiring) {
|
||||
if (currentOffset == _size) {
|
||||
if (remaining > 0) {
|
||||
throw new IllegalStateException("reached end of document stream unexpectedly");
|
||||
}
|
||||
currentBlock = null;
|
||||
break;
|
||||
}
|
||||
currentBlock = getDataInputBlock(currentOffset);
|
||||
blockAvailable = currentBlock.available();
|
||||
}
|
||||
else
|
||||
{
|
||||
DocumentBlock.read(_big_store.getBlocks(), buffer, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DocumentProperty
|
||||
*
|
||||
* @return <code>null</code> if <tt>offset</tt> points to the end of the document stream
|
||||
*/
|
||||
DataInputBlock getDataInputBlock(int offset) {
|
||||
if (offset >= _size) {
|
||||
if (offset > _size) {
|
||||
throw new RuntimeException("Request for Offset " + offset + " doc size is " + _size);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (_property.shouldUseSmallBlocks()) {
|
||||
return SmallDocumentBlock.getDataInputBlock(_small_store.getBlocks(), offset);
|
||||
} else {
|
||||
return DocumentBlock.getDataInputBlock(_big_store.getBlocks(), offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the instance's DocumentProperty
|
||||
*/
|
||||
|
||||
DocumentProperty getDocumentProperty()
|
||||
{
|
||||
DocumentProperty getDocumentProperty() {
|
||||
return _property;
|
||||
}
|
||||
|
||||
@ -262,16 +267,9 @@ public class POIFSDocument
|
||||
/**
|
||||
* Write the storage to an OutputStream
|
||||
*
|
||||
* @param stream the OutputStream to which the stored data should
|
||||
* be written
|
||||
*
|
||||
* @exception IOException on problems writing to the specified
|
||||
* stream
|
||||
* @param stream the OutputStream to which the stored data should be written
|
||||
*/
|
||||
|
||||
public void writeBlocks(final OutputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
public void writeBlocks(OutputStream stream) throws IOException {
|
||||
_big_store.writeBlocks(stream);
|
||||
}
|
||||
|
||||
@ -283,21 +281,16 @@ public class POIFSDocument
|
||||
*
|
||||
* @return count of BigBlock instances
|
||||
*/
|
||||
|
||||
public int countBlocks()
|
||||
{
|
||||
public int countBlocks() {
|
||||
return _big_store.countBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start block for this instance
|
||||
*
|
||||
* @param index index into the array of blocks making up the
|
||||
* filesystem
|
||||
* @param index index into the array of blocks making up the filesystem
|
||||
*/
|
||||
|
||||
public void setStartBlock(final int index)
|
||||
{
|
||||
public void setStartBlock(int index) {
|
||||
_property.setStartBlock(index);
|
||||
}
|
||||
|
||||
@ -305,41 +298,31 @@ public class POIFSDocument
|
||||
/* ********** START begin implementation of POIFSViewable ********** */
|
||||
|
||||
/**
|
||||
* Get an array of objects, some of which may implement
|
||||
* POIFSViewable
|
||||
* Get an array of objects, some of which may implement POIFSViewable
|
||||
*
|
||||
* @return an array of Object; may not be null, but may be empty
|
||||
*/
|
||||
|
||||
public Object [] getViewableArray()
|
||||
{
|
||||
Object[] results = new Object[ 1 ];
|
||||
public Object[] getViewableArray() {
|
||||
Object[] results = new Object[1];
|
||||
String result;
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
BlockWritable[] blocks = null;
|
||||
|
||||
if (_big_store.isValid())
|
||||
{
|
||||
if (_big_store.isValid()) {
|
||||
blocks = _big_store.getBlocks();
|
||||
}
|
||||
else if (_small_store.isValid())
|
||||
{
|
||||
} else if (_small_store.isValid()) {
|
||||
blocks = _small_store.getBlocks();
|
||||
}
|
||||
if (blocks != null)
|
||||
{
|
||||
for (int k = 0; k < blocks.length; k++)
|
||||
{
|
||||
blocks[ k ].writeBlocks(output);
|
||||
if (blocks != null) {
|
||||
for (int k = 0; k < blocks.length; k++) {
|
||||
blocks[k].writeBlocks(output);
|
||||
}
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
if (data.length > _property.getSize())
|
||||
{
|
||||
byte[] tmp = new byte[ _property.getSize() ];
|
||||
if (data.length > _property.getSize()) {
|
||||
byte[] tmp = new byte[_property.getSize()];
|
||||
|
||||
System.arraycopy(data, 0, tmp, 0, tmp.length);
|
||||
data = tmp;
|
||||
@ -347,30 +330,23 @@ public class POIFSDocument
|
||||
output = new ByteArrayOutputStream();
|
||||
HexDump.dump(data, 0, output, 0);
|
||||
result = output.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
result = "<NO DATA>";
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
} catch (IOException e) {
|
||||
result = e.getMessage();
|
||||
}
|
||||
results[ 0 ] = result;
|
||||
results[0] = result;
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Iterator of objects, some of which may implement
|
||||
* POIFSViewable
|
||||
* Get an Iterator of objects, some of which may implement POIFSViewable
|
||||
*
|
||||
* @return an Iterator; may not be null, but may have an empty
|
||||
* back end store
|
||||
* @return an Iterator; may not be null, but may have an empty back end
|
||||
* store
|
||||
*/
|
||||
|
||||
public Iterator getViewableIterator()
|
||||
{
|
||||
public Iterator getViewableIterator() {
|
||||
return Collections.EMPTY_LIST.iterator();
|
||||
}
|
||||
|
||||
@ -378,12 +354,10 @@ public class POIFSDocument
|
||||
* Give viewers a hint as to whether to call getViewableArray or
|
||||
* getViewableIterator
|
||||
*
|
||||
* @return true if a viewer should call getViewableArray, false if
|
||||
* a viewer should call getViewableIterator
|
||||
* @return <code>true</code> if a viewer should call getViewableArray,
|
||||
* <code>false</code> if a viewer should call getViewableIterator
|
||||
*/
|
||||
|
||||
public boolean preferArray()
|
||||
{
|
||||
public boolean preferArray() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -393,39 +367,29 @@ public class POIFSDocument
|
||||
*
|
||||
* @return short description
|
||||
*/
|
||||
|
||||
public String getShortDescription()
|
||||
{
|
||||
public String getShortDescription() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("Document: \"").append(_property.getName())
|
||||
.append("\"");
|
||||
buffer.append("Document: \"").append(_property.getName()).append("\"");
|
||||
buffer.append(" size = ").append(getSize());
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/* ********** END begin implementation of POIFSViewable ********** */
|
||||
private class SmallBlockStore
|
||||
{
|
||||
private static final class SmallBlockStore {
|
||||
private SmallDocumentBlock[] smallBlocks;
|
||||
private POIFSDocumentPath path;
|
||||
private String name;
|
||||
private int size;
|
||||
private POIFSWriterListener writer;
|
||||
private final POIFSDocumentPath path;
|
||||
private final String name;
|
||||
private final int size;
|
||||
private final POIFSWriterListener writer;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param blocks blocks to construct the store from
|
||||
*/
|
||||
|
||||
SmallBlockStore(final Object [] blocks)
|
||||
{
|
||||
smallBlocks = new SmallDocumentBlock[ blocks.length ];
|
||||
for (int j = 0; j < blocks.length; j++)
|
||||
{
|
||||
smallBlocks[ j ] = ( SmallDocumentBlock ) blocks[ j ];
|
||||
}
|
||||
SmallBlockStore(SmallDocumentBlock[] blocks) {
|
||||
smallBlocks = (SmallDocumentBlock[]) blocks.clone();
|
||||
this.path = null;
|
||||
this.name = null;
|
||||
this.size = -1;
|
||||
@ -433,19 +397,15 @@ public class POIFSDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a small block store that will be written
|
||||
* later
|
||||
* Constructor for a small block store that will be written later
|
||||
*
|
||||
* @param path path of the document
|
||||
* @param name name of the document
|
||||
* @param size length of the document
|
||||
* @param writer the object that will eventually write the document
|
||||
*/
|
||||
|
||||
SmallBlockStore(final POIFSDocumentPath path, final String name,
|
||||
final int size, final POIFSWriterListener writer)
|
||||
{
|
||||
smallBlocks = new SmallDocumentBlock[ 0 ];
|
||||
SmallBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
|
||||
smallBlocks = new SmallDocumentBlock[0];
|
||||
this.path = path;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
@ -453,68 +413,41 @@ public class POIFSDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this store is a valid source of data
|
||||
* @return <code>true</code> if this store is a valid source of data
|
||||
*/
|
||||
|
||||
boolean isValid()
|
||||
{
|
||||
return ((smallBlocks.length > 0) || (writer != null));
|
||||
boolean isValid() {
|
||||
return smallBlocks.length > 0 || writer != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the SmallDocumentBlocks
|
||||
*/
|
||||
SmallDocumentBlock[] getBlocks() {
|
||||
if (isValid() && writer != null) {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
|
||||
DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
|
||||
|
||||
BlockWritable [] getBlocks()
|
||||
{
|
||||
if (isValid() && (writer != null))
|
||||
{
|
||||
ByteArrayOutputStream stream =
|
||||
new ByteArrayOutputStream(size);
|
||||
DocumentOutputStream dstream =
|
||||
new DocumentOutputStream(stream, size);
|
||||
|
||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
|
||||
path, name, size));
|
||||
smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(),
|
||||
size);
|
||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
|
||||
smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(), size);
|
||||
}
|
||||
return smallBlocks;
|
||||
}
|
||||
} // end private class SmallBlockStore
|
||||
|
||||
private class BigBlockStore
|
||||
{
|
||||
private static final class BigBlockStore {
|
||||
private DocumentBlock[] bigBlocks;
|
||||
private POIFSDocumentPath path;
|
||||
private String name;
|
||||
private int size;
|
||||
private POIFSWriterListener writer;
|
||||
private final POIFSDocumentPath path;
|
||||
private final String name;
|
||||
private final int size;
|
||||
private final POIFSWriterListener writer;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param blocks the blocks making up the store
|
||||
*
|
||||
* @exception IOException on I/O error
|
||||
*/
|
||||
|
||||
BigBlockStore(final Object [] blocks)
|
||||
throws IOException
|
||||
{
|
||||
bigBlocks = new DocumentBlock[ blocks.length ];
|
||||
for (int j = 0; j < blocks.length; j++)
|
||||
{
|
||||
if (blocks[ j ] instanceof DocumentBlock)
|
||||
{
|
||||
bigBlocks[ j ] = ( DocumentBlock ) blocks[ j ];
|
||||
}
|
||||
else
|
||||
{
|
||||
bigBlocks[ j ] =
|
||||
new DocumentBlock(( RawDataBlock ) blocks[ j ]);
|
||||
}
|
||||
}
|
||||
BigBlockStore(DocumentBlock[] blocks) {
|
||||
bigBlocks = (DocumentBlock[]) blocks.clone();
|
||||
this.path = null;
|
||||
this.name = null;
|
||||
this.size = -1;
|
||||
@ -522,20 +455,15 @@ public class POIFSDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a big block store that will be written
|
||||
* later
|
||||
* Constructor for a big block store that will be written later
|
||||
*
|
||||
* @param path path of the document
|
||||
* @param name name of the document
|
||||
* @param size length of the document
|
||||
* @param writer the object that will eventually write the
|
||||
* document
|
||||
* @param writer the object that will eventually write the document
|
||||
*/
|
||||
|
||||
BigBlockStore(final POIFSDocumentPath path, final String name,
|
||||
final int size, final POIFSWriterListener writer)
|
||||
{
|
||||
bigBlocks = new DocumentBlock[ 0 ];
|
||||
BigBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
|
||||
bigBlocks = new DocumentBlock[0];
|
||||
this.path = path;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
@ -543,29 +471,21 @@ public class POIFSDocument
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this store is a valid source of data
|
||||
* @return <code>true</code> if this store is a valid source of data
|
||||
*/
|
||||
|
||||
boolean isValid()
|
||||
{
|
||||
return ((bigBlocks.length > 0) || (writer != null));
|
||||
boolean isValid() {
|
||||
return bigBlocks.length > 0 || writer != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the DocumentBlocks
|
||||
*/
|
||||
DocumentBlock[] getBlocks() {
|
||||
if (isValid() && writer != null) {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
|
||||
DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
|
||||
|
||||
DocumentBlock [] getBlocks()
|
||||
{
|
||||
if (isValid() && (writer != null))
|
||||
{
|
||||
ByteArrayOutputStream stream =
|
||||
new ByteArrayOutputStream(size);
|
||||
DocumentOutputStream dstream =
|
||||
new DocumentOutputStream(stream, size);
|
||||
|
||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
|
||||
path, name, size));
|
||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
|
||||
bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
|
||||
}
|
||||
return bigBlocks;
|
||||
@ -575,32 +495,18 @@ public class POIFSDocument
|
||||
* write the blocks to a stream
|
||||
*
|
||||
* @param stream the stream to which the data is to be written
|
||||
*
|
||||
* @exception IOException on error
|
||||
*/
|
||||
void writeBlocks(OutputStream stream) throws IOException {
|
||||
if (isValid()) {
|
||||
if (writer != null) {
|
||||
DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
|
||||
|
||||
void writeBlocks(OutputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
if (writer != null)
|
||||
{
|
||||
DocumentOutputStream dstream =
|
||||
new DocumentOutputStream(stream, size);
|
||||
|
||||
writer.processPOIFSWriterEvent(
|
||||
new POIFSWriterEvent(dstream, path, name, size));
|
||||
dstream.writeFiller(countBlocks()
|
||||
* POIFSConstants
|
||||
.BIG_BLOCK_SIZE, DocumentBlock
|
||||
.getFillByte());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int k = 0; k < bigBlocks.length; k++)
|
||||
{
|
||||
bigBlocks[ k ].writeBlocks(stream);
|
||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
|
||||
dstream.writeFiller(countBlocks() * POIFSConstants.BIG_BLOCK_SIZE,
|
||||
DocumentBlock.getFillByte());
|
||||
} else {
|
||||
for (int k = 0; k < bigBlocks.length; k++) {
|
||||
bigBlocks[k].writeBlocks(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -609,25 +515,16 @@ public class POIFSDocument
|
||||
/**
|
||||
* @return number of big blocks making up this document
|
||||
*/
|
||||
int countBlocks() {
|
||||
|
||||
int countBlocks()
|
||||
{
|
||||
int rval = 0;
|
||||
|
||||
if (isValid())
|
||||
{
|
||||
if (writer != null)
|
||||
{
|
||||
rval = (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
|
||||
if (isValid()) {
|
||||
if (writer == null) {
|
||||
return bigBlocks.length;
|
||||
}
|
||||
return (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
|
||||
/ POIFSConstants.BIG_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = bigBlocks.length;
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
return 0;
|
||||
}
|
||||
} // end private class BigBlockStore
|
||||
} // end class POIFSDocument
|
||||
|
||||
}
|
||||
|
186
src/java/org/apache/poi/poifs/storage/DataInputBlock.java
Normal file
186
src/java/org/apache/poi/poifs/storage/DataInputBlock.java
Normal 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;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,30 +15,26 @@
|
||||
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 ********** */
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,12 +15,14 @@
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,49 +55,11 @@ 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;
|
||||
public static int getUShort(byte[] data, int offset) {
|
||||
int b0 = data[offset] & 0xFF;
|
||||
int b1 = data[offset+1] & 0xFF;
|
||||
return (b1 << 8) + (b0 << 0);
|
||||
}
|
||||
return retNum;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get a short array from a byte array.
|
||||
*
|
||||
*@param data Description of the Parameter
|
||||
*@param offset Description of the Parameter
|
||||
*@param size Description of the Parameter
|
||||
*@return The simpleShortArray value
|
||||
*/
|
||||
public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) {
|
||||
short[] results = new short[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
results[i] = getShort(data, offset + 2 + (i * 2));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get a short array from a byte array. The short array is assumed to start
|
||||
* with a word describing the length of the array.
|
||||
*
|
||||
*@param data Description of the Parameter
|
||||
*@param offset Description of the Parameter
|
||||
*@return The shortArray value
|
||||
*/
|
||||
public static short[] getShortArray(final byte[] data, final int offset) {
|
||||
int size = (int) getNumber(data, offset, SHORT_SIZE);
|
||||
short[] results = getSimpleShortArray(data, offset, size);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get a short value from the beginning of a byte array
|
||||
@ -105,23 +67,20 @@ public final class LittleEndian implements LittleEndianConsts {
|
||||
*@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);
|
||||
}
|
||||
|
||||
|
||||
@ -141,8 +104,7 @@ public final class LittleEndian implements LittleEndianConsts {
|
||||
*@param data the byte array
|
||||
*@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,7 +127,7 @@ 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) {
|
||||
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(byte[] data, int offset) {
|
||||
long result = 0;
|
||||
|
||||
public static long getLong(final byte[] data, final int offset) {
|
||||
return getNumber(data, offset, LONG_SIZE);
|
||||
for (int j = offset + LONG_SIZE - 1; j >= offset; j--) {
|
||||
result <<= 8;
|
||||
result |= 0xff & data[j];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get a double value from a byte array, reads it in little endian format
|
||||
* then converts the resulting revolting IEEE 754 (curse them) floating
|
||||
@ -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(byte[] data, int offset, long value) {
|
||||
int limit = LONG_SIZE + offset;
|
||||
long v = value;
|
||||
|
||||
public static void putLong(final byte[] data, final int offset,
|
||||
final long value) {
|
||||
putNumber(data, offset, value, LONG_SIZE);
|
||||
for (int j = offset; j < limit; j++) {
|
||||
data[j] = (byte) (v & 0xFF);
|
||||
v >>= 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
if (Double.isNaN(value)) {
|
||||
putLong(data, offset, -276939487313920L);
|
||||
} else {
|
||||
putLong(data, offset, Double.doubleToLongBits(value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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,12 +289,10 @@ 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 {
|
||||
|
||||
@ -395,21 +306,19 @@ public final class LittleEndian implements LittleEndianConsts {
|
||||
if ((ch1 | ch2) < 0) {
|
||||
throw new BufferUnderrunException();
|
||||
}
|
||||
return ((ch2 << 8) + (ch1 << 0));
|
||||
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();
|
||||
@ -418,22 +327,19 @@ public final class LittleEndian implements LittleEndianConsts {
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0) {
|
||||
throw new BufferUnderrunException();
|
||||
}
|
||||
return ((ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0));
|
||||
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();
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -221,6 +219,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.
|
||||
* Primarily used for logging.
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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++) {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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() );
|
||||
|
@ -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);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,17 +15,15 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import junit.framework.TestSuite;
|
||||
public final class AllPOIFSStorageTests {
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite result = new TestSuite("Tests for org.apache.poi.poifs.storage");
|
||||
TestSuite result = new TestSuite(AllPOIFSStorageTests.class.getName());
|
||||
result.addTestSuite(TestBATBlock.class);
|
||||
result.addTestSuite(TestBlockAllocationTableReader.class);
|
||||
result.addTestSuite(TestBlockAllocationTableWriter.class);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,24 +15,20 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,24 +15,23 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user