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
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,10 +15,8 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.contrib.poibrowser;
|
package org.apache.poi.contrib.poibrowser;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -160,17 +157,7 @@ public class TreeReaderListener implements POIFSReaderListener
|
|||||||
throw new RuntimeException(t.getMessage());
|
throw new RuntimeException(t.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
is.close();
|
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 parentNode = getNode(d.path, filename, rootNode);
|
||||||
final MutableTreeNode nameNode = new DefaultMutableTreeNode(d.name);
|
final MutableTreeNode nameNode = new DefaultMutableTreeNode(d.name);
|
||||||
|
@ -788,7 +788,7 @@ public final class Workbook implements Model {
|
|||||||
if(r instanceof ExtendedFormatRecord) {
|
if(r instanceof ExtendedFormatRecord) {
|
||||||
} else if(r instanceof StyleRecord) {
|
} else if(r instanceof StyleRecord) {
|
||||||
StyleRecord sr = (StyleRecord)r;
|
StyleRecord sr = (StyleRecord)r;
|
||||||
if(sr.getIndex() == xfIndex) {
|
if(sr.getXFIndex() == xfIndex) {
|
||||||
return sr;
|
return sr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -806,7 +806,7 @@ public final class Workbook implements Model {
|
|||||||
// Style records always follow after
|
// Style records always follow after
|
||||||
// the ExtendedFormat records
|
// the ExtendedFormat records
|
||||||
StyleRecord newSR = new StyleRecord();
|
StyleRecord newSR = new StyleRecord();
|
||||||
newSR.setIndex((short)xfIndex);
|
newSR.setXFIndex(xfIndex);
|
||||||
|
|
||||||
// Find the spot
|
// Find the spot
|
||||||
int addAt = -1;
|
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.StyleRecord
|
||||||
* @see org.apache.poi.hssf.record.Record
|
* @see org.apache.poi.hssf.record.Record
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected Record createStyle(int id) { // we'll need multiple editions
|
protected Record createStyle(int id) { // we'll need multiple editions
|
||||||
StyleRecord retval = new StyleRecord();
|
StyleRecord retval = new StyleRecord();
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
|
||||||
case 0 :
|
case 0 :
|
||||||
retval.setIndex(( short ) 0xffff8010);
|
retval.setXFIndex(0x010);
|
||||||
retval.setBuiltin(( byte ) 3);
|
retval.setBuiltinStyle(3);
|
||||||
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1 :
|
case 1 :
|
||||||
retval.setIndex(( short ) 0xffff8011);
|
retval.setXFIndex(0x011);
|
||||||
retval.setBuiltin(( byte ) 6);
|
retval.setBuiltinStyle(6);
|
||||||
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2 :
|
case 2 :
|
||||||
retval.setIndex(( short ) 0xffff8012);
|
retval.setXFIndex(0x012);
|
||||||
retval.setBuiltin(( byte ) 4);
|
retval.setBuiltinStyle(4);
|
||||||
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3 :
|
case 3 :
|
||||||
retval.setIndex(( short ) 0xffff8013);
|
retval.setXFIndex(0x013);
|
||||||
retval.setBuiltin(( byte ) 7);
|
retval.setBuiltinStyle(7);
|
||||||
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4 :
|
case 4 :
|
||||||
retval.setIndex(( short ) 0xffff8000);
|
retval.setXFIndex(0x000);
|
||||||
retval.setBuiltin(( byte ) 0);
|
retval.setBuiltinStyle(0);
|
||||||
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5 :
|
case 5 :
|
||||||
retval.setIndex(( short ) 0xffff8014);
|
retval.setXFIndex(0x014);
|
||||||
retval.setBuiltin(( byte ) 5);
|
retval.setBuiltinStyle(5);
|
||||||
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
retval.setOutlineStyleLevel(( byte ) 0xffffffff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,18 @@
|
|||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.constant.ConstantValueParser;
|
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>
|
* Title: CRN(0x005A) <p/>
|
||||||
* Description: This record stores the contents of an external cell or cell range <P>
|
* Description: This record stores the contents of an external cell or cell range <p/>
|
||||||
* REFERENCE: 5.23<P>
|
* REFERENCE: OOO 5.23<p/>
|
||||||
*
|
*
|
||||||
* @author josh micich
|
* @author josh micich
|
||||||
*/
|
*/
|
||||||
public final class CRNRecord extends Record {
|
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_1_last_column_index;
|
||||||
private int field_2_first_column_index;
|
private int field_2_first_column_index;
|
||||||
@ -45,8 +46,8 @@ public final class CRNRecord extends Record {
|
|||||||
|
|
||||||
|
|
||||||
public CRNRecord(RecordInputStream in) {
|
public CRNRecord(RecordInputStream in) {
|
||||||
field_1_last_column_index = in.readByte() & 0x00FF;
|
field_1_last_column_index = in.readUByte();
|
||||||
field_2_first_column_index = in.readByte() & 0x00FF;
|
field_2_first_column_index = in.readUByte();
|
||||||
field_3_row_index = in.readShort();
|
field_3_row_index = in.readShort();
|
||||||
int nValues = field_1_last_column_index - field_2_first_column_index + 1;
|
int nValues = field_1_last_column_index - field_2_first_column_index + 1;
|
||||||
field_4_constant_values = ConstantValueParser.parse(in, nValues);
|
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) {
|
public int serialize(int offset, byte [] data) {
|
||||||
int dataSize = getDataSize();
|
int dataSize = getDataSize();
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
int recSize = 4 + dataSize;
|
||||||
LittleEndian.putShort(data, 2 + offset, (short) dataSize);
|
LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
|
||||||
LittleEndian.putByte(data, 4 + offset, field_1_last_column_index);
|
out.writeShort(sid);
|
||||||
LittleEndian.putByte(data, 5 + offset, field_2_first_column_index);
|
out.writeShort(dataSize);
|
||||||
LittleEndian.putShort(data, 6 + offset, (short) field_3_row_index);
|
out.writeByte(field_1_last_column_index);
|
||||||
ConstantValueParser.encode(data, 8 + offset, field_4_constant_values);
|
out.writeByte(field_2_first_column_index);
|
||||||
return getRecordSize();
|
out.writeShort(field_3_row_index);
|
||||||
|
ConstantValueParser.encode(out, field_4_constant_values);
|
||||||
|
return recSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRecordSize() {
|
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.HexDump;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianInput;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
@ -111,10 +112,10 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
|
|||||||
field_3_unicode_flag = ( in.readByte() & 0x01 ) != 0;
|
field_3_unicode_flag = ( in.readByte() & 0x01 ) != 0;
|
||||||
remaining -= LittleEndian.BYTE_SIZE;
|
remaining -= LittleEndian.BYTE_SIZE;
|
||||||
if (field_3_unicode_flag) {
|
if (field_3_unicode_flag) {
|
||||||
field_4_ole_classname = in.readUnicodeLEString(nChars);
|
field_4_ole_classname = StringUtil.readUnicodeLE(in, nChars);
|
||||||
stringByteCount = nChars * 2;
|
stringByteCount = nChars * 2;
|
||||||
} else {
|
} else {
|
||||||
field_4_ole_classname = in.readCompressedUnicode(nChars);
|
field_4_ole_classname = StringUtil.readCompressedUnicode(in, nChars);
|
||||||
stringByteCount = nChars;
|
stringByteCount = nChars;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -156,12 +157,7 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Ptg readRefPtg(byte[] formulaRawBytes) {
|
private static Ptg readRefPtg(byte[] formulaRawBytes) {
|
||||||
byte[] data = new byte[formulaRawBytes.length + 4];
|
LittleEndianInput in = new LittleEndianInputStream(new ByteArrayInputStream(formulaRawBytes));
|
||||||
LittleEndian.putUShort(data, 0, -5555);
|
|
||||||
LittleEndian.putUShort(data, 2, formulaRawBytes.length);
|
|
||||||
System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
|
|
||||||
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
|
|
||||||
in.nextRecord();
|
|
||||||
byte ptgSid = in.readByte();
|
byte ptgSid = in.readByte();
|
||||||
switch(ptgSid) {
|
switch(ptgSid) {
|
||||||
case AreaPtg.sid: return new AreaPtg(in);
|
case AreaPtg.sid: return new AreaPtg(in);
|
||||||
|
@ -51,7 +51,7 @@ public final class LinkedDataFormulaField {
|
|||||||
.append( "=" )
|
.append( "=" )
|
||||||
.append(ptg.toString() )
|
.append(ptg.toString() )
|
||||||
.append( "\n" )
|
.append( "\n" )
|
||||||
.append(ptg.toDebugString() )
|
.append(ptg.toString())
|
||||||
.append( "\n" );
|
.append( "\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
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.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianInput;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title: Record Input Stream<P>
|
* 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*/
|
/** Maximum size of a single record (minus the 4 byte header) without a continue*/
|
||||||
public final static short MAX_RECORD_DATA_SIZE = 8224;
|
public final static short MAX_RECORD_DATA_SIZE = 8224;
|
||||||
private static final int INVALID_SID_VALUE = -1;
|
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;
|
/** {@link LittleEndianInput} facet of the wrapped {@link InputStream} */
|
||||||
private short currentSid;
|
private final LittleEndianInput _le;
|
||||||
private short currentLength = -1;
|
/** the record identifier of the BIFF record currently being read */
|
||||||
private short nextSid;
|
private int _currentSid;
|
||||||
|
/**
|
||||||
private final byte[] data = new byte[MAX_RECORD_DATA_SIZE];
|
* Length of the data section of the current BIFF record (always 4 less than the total record size).
|
||||||
private short recordOffset;
|
* When uninitialised, this field is set to {@link #DATA_LEN_NEEDS_TO_BE_READ}.
|
||||||
private long pos;
|
*/
|
||||||
|
private int _currentDataLength;
|
||||||
private boolean autoContinue = true;
|
/**
|
||||||
|
* 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 {
|
public RecordInputStream(InputStream in) throws RecordFormatException {
|
||||||
this.in = in;
|
if (in instanceof LittleEndianInput) {
|
||||||
try {
|
// accessing directly is an optimisation
|
||||||
nextSid = LittleEndian.readShort(in);
|
_le = (LittleEndianInput) in;
|
||||||
//Don't increment the pos just yet (technically we are at the start of
|
} else {
|
||||||
//the record stream until nextRecord is called).
|
// less optimal, but should work OK just the same. Often occurs in junit tests.
|
||||||
} catch (IOException ex) {
|
_le = new LittleEndianInputStream(in);
|
||||||
throw new RecordFormatException("Error reading bytes", ex);
|
|
||||||
}
|
}
|
||||||
|
_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() {
|
public int read() {
|
||||||
checkRecordPosition(LittleEndian.BYTE_SIZE);
|
checkRecordPosition(LittleEndian.BYTE_SIZE);
|
||||||
|
_currentDataOffset += LittleEndian.BYTE_SIZE;
|
||||||
byte result = data[recordOffset];
|
return _le.readUByte();
|
||||||
recordOffset += LittleEndian.BYTE_SIZE;
|
}
|
||||||
pos += LittleEndian.BYTE_SIZE;
|
public int read(byte[] b, int off, int len) {
|
||||||
return result;
|
int limit = Math.min(len, remaining());
|
||||||
|
if (limit == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
readFully(b, off,limit);
|
||||||
|
return limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid() {
|
public short getSid() {
|
||||||
return currentSid;
|
return (short) _currentSid;
|
||||||
}
|
|
||||||
|
|
||||||
public short getLength() {
|
|
||||||
return currentLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getRecordOffset() {
|
|
||||||
return recordOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPos() {
|
|
||||||
return pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
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.
|
/** 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>
|
* <i>Note: The auto continue flag is reset to true</i>
|
||||||
*/
|
*/
|
||||||
public void nextRecord() throws RecordFormatException {
|
public void nextRecord() throws RecordFormatException {
|
||||||
if ((currentLength != -1) && (currentLength != recordOffset)) {
|
if (_nextSid == INVALID_SID_VALUE) {
|
||||||
System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(currentSid));
|
throw new IllegalStateException("EOF - next record not available");
|
||||||
}
|
}
|
||||||
currentSid = nextSid;
|
if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
|
||||||
pos += LittleEndian.SHORT_SIZE;
|
throw new IllegalStateException("Cannot call nextRecord() without checking hasNextRecord() first");
|
||||||
autoContinue = true;
|
|
||||||
try {
|
|
||||||
recordOffset = 0;
|
|
||||||
currentLength = LittleEndian.readShort(in);
|
|
||||||
if (currentLength > MAX_RECORD_DATA_SIZE)
|
|
||||||
throw new RecordFormatException("The content of an excel record cannot exceed "+MAX_RECORD_DATA_SIZE+" bytes");
|
|
||||||
pos += LittleEndian.SHORT_SIZE;
|
|
||||||
in.read(data, 0, currentLength);
|
|
||||||
|
|
||||||
//Read the Sid of the next record
|
|
||||||
if (in.available() < EOFRecord.ENCODED_SIZE) {
|
|
||||||
if (in.available() > 0) {
|
|
||||||
// some scrap left over?
|
|
||||||
// ex45582-22397.xls has one extra byte after the last record
|
|
||||||
// Excel reads that file OK
|
|
||||||
}
|
}
|
||||||
nextSid = INVALID_SID_VALUE;
|
_currentSid = _nextSid;
|
||||||
} else {
|
_currentDataOffset = 0;
|
||||||
nextSid = LittleEndian.readShort(in);
|
_currentDataLength = _le.readUShort();
|
||||||
if (nextSid == INVALID_SID_VALUE) {
|
if (_currentDataLength > MAX_RECORD_DATA_SIZE) {
|
||||||
throw new RecordFormatException("Found sid " + nextSid + " after record with sid 0x"
|
throw new RecordFormatException("The content of an excel record cannot exceed "
|
||||||
+ Integer.toHexString(currentSid).toUpperCase());
|
+ 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) {
|
private void checkRecordPosition(int requiredByteCount) {
|
||||||
|
|
||||||
if (remaining() < requiredByteCount) {
|
int nAvailable = remaining();
|
||||||
if (isContinueNext() && autoContinue) {
|
if (nAvailable >= requiredByteCount) {
|
||||||
|
// all OK
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (nAvailable == 0 && isContinueNext()) {
|
||||||
nextRecord();
|
nextRecord();
|
||||||
} else {
|
return;
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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() {
|
public byte readByte() {
|
||||||
checkRecordPosition(LittleEndian.BYTE_SIZE);
|
checkRecordPosition(LittleEndian.BYTE_SIZE);
|
||||||
|
_currentDataOffset += LittleEndian.BYTE_SIZE;
|
||||||
byte result = data[recordOffset];
|
return _le.readByte();
|
||||||
recordOffset += LittleEndian.BYTE_SIZE;
|
|
||||||
pos += LittleEndian.BYTE_SIZE;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,29 +191,20 @@ public final class RecordInputStream extends InputStream implements LittleEndian
|
|||||||
*/
|
*/
|
||||||
public short readShort() {
|
public short readShort() {
|
||||||
checkRecordPosition(LittleEndian.SHORT_SIZE);
|
checkRecordPosition(LittleEndian.SHORT_SIZE);
|
||||||
|
_currentDataOffset += LittleEndian.SHORT_SIZE;
|
||||||
short result = LittleEndian.getShort(data, recordOffset);
|
return _le.readShort();
|
||||||
recordOffset += LittleEndian.SHORT_SIZE;
|
|
||||||
pos += LittleEndian.SHORT_SIZE;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readInt() {
|
public int readInt() {
|
||||||
checkRecordPosition(LittleEndian.INT_SIZE);
|
checkRecordPosition(LittleEndian.INT_SIZE);
|
||||||
|
_currentDataOffset += LittleEndian.INT_SIZE;
|
||||||
int result = LittleEndian.getInt(data, recordOffset);
|
return _le.readInt();
|
||||||
recordOffset += LittleEndian.INT_SIZE;
|
|
||||||
pos += LittleEndian.INT_SIZE;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long readLong() {
|
public long readLong() {
|
||||||
checkRecordPosition(LittleEndian.LONG_SIZE);
|
checkRecordPosition(LittleEndian.LONG_SIZE);
|
||||||
|
_currentDataOffset += LittleEndian.LONG_SIZE;
|
||||||
long result = LittleEndian.getLong(data, recordOffset);
|
return _le.readLong();
|
||||||
recordOffset += LittleEndian.LONG_SIZE;
|
|
||||||
pos += LittleEndian.LONG_SIZE;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,22 +220,18 @@ public final class RecordInputStream extends InputStream implements LittleEndian
|
|||||||
*/
|
*/
|
||||||
public int readUShort() {
|
public int readUShort() {
|
||||||
checkRecordPosition(LittleEndian.SHORT_SIZE);
|
checkRecordPosition(LittleEndian.SHORT_SIZE);
|
||||||
|
_currentDataOffset += LittleEndian.SHORT_SIZE;
|
||||||
int result = LittleEndian.getUShort(data, recordOffset);
|
return _le.readUShort();
|
||||||
recordOffset += LittleEndian.SHORT_SIZE;
|
|
||||||
pos += LittleEndian.SHORT_SIZE;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public double readDouble() {
|
public double readDouble() {
|
||||||
checkRecordPosition(LittleEndian.DOUBLE_SIZE);
|
checkRecordPosition(LittleEndian.DOUBLE_SIZE);
|
||||||
long valueLongBits = LittleEndian.getLong(data, recordOffset);
|
_currentDataOffset += LittleEndian.DOUBLE_SIZE;
|
||||||
|
long valueLongBits = _le.readLong();
|
||||||
double result = Double.longBitsToDouble(valueLongBits);
|
double result = Double.longBitsToDouble(valueLongBits);
|
||||||
if (Double.isNaN(result)) {
|
if (Double.isNaN(result)) {
|
||||||
throw new RuntimeException("Did not expect to read NaN"); // (Because Excel typically doesn't write NaN
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
public void readFully(byte[] buf) {
|
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) {
|
public void readFully(byte[] buf, int off, int len) {
|
||||||
checkRecordPosition(len);
|
checkRecordPosition(len);
|
||||||
System.arraycopy(data, recordOffset, buf, off, len);
|
_le.readFully(buf, off, len);
|
||||||
recordOffset+=len;
|
_currentDataOffset+=len;
|
||||||
pos+=len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String readString() {
|
public String readString() {
|
||||||
@ -321,10 +336,11 @@ public final class RecordInputStream extends InputStream implements LittleEndian
|
|||||||
*/
|
*/
|
||||||
public byte[] readRemainder() {
|
public byte[] readRemainder() {
|
||||||
int size = remaining();
|
int size = remaining();
|
||||||
|
if (size ==0) {
|
||||||
|
return EMPTY_BYTE_ARRAY;
|
||||||
|
}
|
||||||
byte[] result = new byte[size];
|
byte[] result = new byte[size];
|
||||||
System.arraycopy(data, recordOffset, result, 0, size);
|
readFully(result);
|
||||||
recordOffset += size;
|
|
||||||
pos += size;
|
|
||||||
return 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
|
* @return The number of bytes remaining in the current record
|
||||||
*/
|
*/
|
||||||
public int remaining() {
|
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() {
|
private boolean isContinueNext() {
|
||||||
return (nextSid == ContinueRecord.sid);
|
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.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.StringUtil;
|
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>
|
* 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>
|
* 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 Andrew C. Oliver (acoliver at apache dot org)
|
||||||
* @author aviks : string fixes for UserDefined Style
|
* @author aviks : string fixes for UserDefined Style
|
||||||
* @version 2.0-pre
|
|
||||||
*/
|
*/
|
||||||
public final class StyleRecord extends Record {
|
public final class StyleRecord extends Record {
|
||||||
public final static short sid = 0x0293;
|
public final static short sid = 0x0293;
|
||||||
|
|
||||||
private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
|
private static final BitField is16BitUnicodeFlag = BitFieldFactory.getInstance(0x01);
|
||||||
|
|
||||||
public final static short STYLE_USER_DEFINED = 0;
|
private static final BitField styleIndexMask = BitFieldFactory.getInstance(0x0FFF);
|
||||||
public final static short STYLE_BUILT_IN = 1;
|
private static final BitField isBuiltinFlag = BitFieldFactory.getInstance(0x8000);
|
||||||
|
|
||||||
// shared by both user defined and builtin styles
|
/** shared by both user defined and built-in styles */
|
||||||
private short field_1_xf_index; // TODO: bitfield candidate
|
private int field_1_xf_index;
|
||||||
|
|
||||||
// only for built in styles
|
// only for built in styles
|
||||||
private byte field_2_builtin_style;
|
private int field_2_builtin_style;
|
||||||
private byte field_3_outline_style_level;
|
private int field_3_outline_style_level;
|
||||||
|
|
||||||
// only for user defined styles
|
// only for user defined styles
|
||||||
private short field_2_name_length; //OO doc says 16 bit length, so we believe
|
private int field_3_string_options;
|
||||||
private byte field_3_string_options;
|
|
||||||
private String field_4_name;
|
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();
|
field_1_xf_index = in.readShort();
|
||||||
if (getType() == STYLE_BUILT_IN)
|
if (isBuiltin()) {
|
||||||
{
|
|
||||||
field_2_builtin_style = in.readByte();
|
field_2_builtin_style = in.readByte();
|
||||||
field_3_outline_style_level = 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 {
|
} 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
|
* set the actual index of the style extended format record
|
||||||
* @see #setIndex(short)
|
* @param xfIndex of the xf record
|
||||||
* @param index of the xf record
|
|
||||||
*/
|
*/
|
||||||
|
public void setXFIndex(int xfIndex) {
|
||||||
public void setXFIndex(short index)
|
field_1_xf_index = styleIndexMask.setValue(field_1_xf_index, xfIndex);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,143 +97,99 @@ public final class StyleRecord extends Record {
|
|||||||
* @see #getIndex()
|
* @see #getIndex()
|
||||||
* @return index of the xf record
|
* @return index of the xf record
|
||||||
*/
|
*/
|
||||||
|
public int getXFIndex() {
|
||||||
public short getXFIndex()
|
return styleIndexMask.getValue(field_1_xf_index);
|
||||||
{
|
|
||||||
return ( short ) (field_1_xf_index & 0x1FFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
* if this is a builtin style set the number of the built in style
|
||||||
* @return length of the style's name
|
* @param builtinStyleId style number (0-7)
|
||||||
* @see #getName()
|
*
|
||||||
*/
|
*/
|
||||||
|
public void setBuiltinStyle(int builtinStyleId) {
|
||||||
|
field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
|
||||||
|
field_2_builtin_style = builtinStyleId;
|
||||||
|
}
|
||||||
|
|
||||||
public short getNameLength()
|
/**
|
||||||
{
|
* set the row or column level of the style (if builtin 1||2)
|
||||||
return field_2_name_length;
|
*/
|
||||||
|
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
|
* get the style's name
|
||||||
* @return name of the style
|
* @return name of the style
|
||||||
* @see #getNameLength()
|
|
||||||
*/
|
*/
|
||||||
|
public String getName() {
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return field_4_name;
|
return field_4_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// end user defined
|
public String toString() {
|
||||||
// only for buildin records
|
StringBuffer sb = new StringBuffer();
|
||||||
|
|
||||||
/**
|
sb.append("[STYLE]\n");
|
||||||
* if this is a builtin style get the number of the built in style
|
sb.append(" .xf_index_raw =").append(HexDump.shortToHex(field_1_xf_index)).append("\n");
|
||||||
* @return builtin style number (0-7)
|
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");
|
||||||
public byte getBuiltin()
|
sb.append(" .outline_level=").append(HexDump.byteToHex(field_3_outline_style_level)).append("\n");
|
||||||
{
|
} else {
|
||||||
return field_2_builtin_style;
|
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()
|
private int getDataSize() {
|
||||||
{
|
if (isBuiltin()) {
|
||||||
return field_3_outline_style_level;
|
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 int serialize(int offset, byte [] data) {
|
||||||
public String toString()
|
int dataSize = getDataSize();
|
||||||
{
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
|
|
||||||
buffer.append("[STYLE]\n");
|
|
||||||
buffer.append(" .xf_index_raw = ")
|
|
||||||
.append(Integer.toHexString(getIndex())).append("\n");
|
|
||||||
buffer.append(" .type = ")
|
|
||||||
.append(Integer.toHexString(getType())).append("\n");
|
|
||||||
buffer.append(" .xf_index = ")
|
|
||||||
.append(Integer.toHexString(getXFIndex())).append("\n");
|
|
||||||
if (getType() == STYLE_BUILT_IN)
|
|
||||||
{
|
|
||||||
buffer.append(" .builtin_style = ")
|
|
||||||
.append(Integer.toHexString(getBuiltin())).append("\n");
|
|
||||||
buffer.append(" .outline_level = ")
|
|
||||||
.append(Integer.toHexString(getOutlineStyleLevel()))
|
|
||||||
.append("\n");
|
|
||||||
}
|
|
||||||
else if (getType() == STYLE_USER_DEFINED)
|
|
||||||
{
|
|
||||||
buffer.append(" .name_length = ")
|
|
||||||
.append(Integer.toHexString(getNameLength())).append("\n");
|
|
||||||
buffer.append(" .name = ").append(getName())
|
|
||||||
.append("\n");
|
|
||||||
}
|
|
||||||
buffer.append("[/STYLE]\n");
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private short setField(int fieldValue, int new_value, int mask,
|
|
||||||
int shiftLeft)
|
|
||||||
{
|
|
||||||
return ( short ) ((fieldValue & ~mask)
|
|
||||||
| ((new_value << shiftLeft) & mask));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int serialize(int offset, byte [] data)
|
|
||||||
{
|
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
if (getType() == STYLE_BUILT_IN)
|
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||||
{
|
|
||||||
LittleEndian.putShort(data, 2 + offset,
|
LittleEndian.putUShort(data, 4 + offset, field_1_xf_index);
|
||||||
(( short ) 0x04)); // 4 bytes (8 total)
|
if (isBuiltin()) {
|
||||||
}
|
LittleEndian.putByte(data, 6 + offset, field_2_builtin_style);
|
||||||
else
|
LittleEndian.putByte(data, 7 + offset, field_3_outline_style_level);
|
||||||
{
|
} else {
|
||||||
LittleEndian.putShort(data, 2 + offset,
|
LittleEndian.putUShort(data, 6 + offset, field_4_name.length());
|
||||||
(( short ) (getRecordSize()-4)));
|
LittleEndian.putByte(data, 8 + offset, field_3_string_options);
|
||||||
}
|
|
||||||
LittleEndian.putShort(data, 4 + offset, getIndex());
|
|
||||||
if (getType() == STYLE_BUILT_IN)
|
|
||||||
{
|
|
||||||
data[ 6 + offset ] = getBuiltin();
|
|
||||||
data[ 7 + offset ] = getOutlineStyleLevel();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LittleEndian.putShort(data, 6 + offset , getNameLength());
|
|
||||||
data[8+offset]=this.field_3_string_options;
|
|
||||||
StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
|
StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
|
||||||
}
|
}
|
||||||
return getRecordSize();
|
return 4+dataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRecordSize()
|
public int getRecordSize() {
|
||||||
{
|
return 4 + getDataSize();
|
||||||
int retval;
|
|
||||||
|
|
||||||
if (getType() == STYLE_BUILT_IN)
|
|
||||||
{
|
|
||||||
retval = 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fHighByte.isSet(field_3_string_options)) {
|
|
||||||
retval= 9+2*getNameLength();
|
|
||||||
}else {
|
|
||||||
retval = 9 + getNameLength();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid()
|
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.hssf.record.formula.RefPtg;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.LittleEndianByteArrayInputStream;
|
||||||
import org.apache.poi.util.LittleEndianInput;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
import org.apache.poi.util.LittleEndianOutputStream;
|
import org.apache.poi.util.LittleEndianOutputStream;
|
||||||
@ -209,12 +210,7 @@ public abstract class SubRecord {
|
|||||||
out.writeShort(_unknownShort13);
|
out.writeShort(_unknownShort13);
|
||||||
}
|
}
|
||||||
private static Ptg readRefPtg(byte[] formulaRawBytes) {
|
private static Ptg readRefPtg(byte[] formulaRawBytes) {
|
||||||
byte[] data = new byte[formulaRawBytes.length + 4];
|
LittleEndianInput in = new LittleEndianByteArrayInputStream(formulaRawBytes);
|
||||||
LittleEndian.putUShort(data, 0, -5555);
|
|
||||||
LittleEndian.putUShort(data, 2, formulaRawBytes.length);
|
|
||||||
System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
|
|
||||||
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
|
|
||||||
in.nextRecord();
|
|
||||||
byte ptgSid = in.readByte();
|
byte ptgSid = in.readByte();
|
||||||
switch(ptgSid) {
|
switch(ptgSid) {
|
||||||
case AreaPtg.sid: return new AreaPtg(in);
|
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)
|
* @param offset of the record's data (provided a big array of the file)
|
||||||
*/
|
*/
|
||||||
public SupBookRecord(RecordInputStream in) {
|
public SupBookRecord(RecordInputStream in) {
|
||||||
|
int recLen = in.remaining();
|
||||||
|
|
||||||
field_1_number_of_sheets = in.readShort();
|
field_1_number_of_sheets = in.readShort();
|
||||||
|
|
||||||
if(in.getLength() > SMALL_RECORD_SIZE) {
|
if(recLen > SMALL_RECORD_SIZE) {
|
||||||
// 5.38.1 External References
|
// 5.38.1 External References
|
||||||
_isAddInFunctions = false;
|
_isAddInFunctions = false;
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ import org.apache.poi.util.BitField;
|
|||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
import org.apache.poi.util.LittleEndian;
|
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
|
* 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);
|
_text = new HSSFRichTextString(text);
|
||||||
|
|
||||||
if (field_7_formattingDataLength > 0) {
|
if (field_7_formattingDataLength > 0) {
|
||||||
if (in.isContinueNext() && in.remaining() == 0) {
|
|
||||||
in.nextRecord();
|
|
||||||
processFontRuns(in, _text, field_7_formattingDataLength);
|
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
|
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;
|
int nRuns = formattingRunDataLength / FORMAT_RUN_ENCODED_SIZE;
|
||||||
for (int i = 0; i < nRuns; i++) {
|
for (int i = 0; i < nRuns; i++) {
|
||||||
short index = in.readShort();
|
short index = in.readShort();
|
||||||
@ -190,36 +182,31 @@ public final class TextObjectRecord extends Record {
|
|||||||
|
|
||||||
private int serializeTXORecord(int offset, byte[] data) {
|
private int serializeTXORecord(int offset, byte[] data) {
|
||||||
int dataSize = getDataSize();
|
int dataSize = getDataSize();
|
||||||
|
int recSize = dataSize+4;
|
||||||
|
LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
|
||||||
|
|
||||||
LittleEndian.putUShort(data, 0 + offset, TextObjectRecord.sid);
|
out.writeShort(TextObjectRecord.sid);
|
||||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
out.writeShort(dataSize);
|
||||||
|
|
||||||
|
out.writeShort(field_1_options);
|
||||||
LittleEndian.putUShort(data, 4 + offset, field_1_options);
|
out.writeShort(field_2_textOrientation);
|
||||||
LittleEndian.putUShort(data, 6 + offset, field_2_textOrientation);
|
out.writeShort(field_3_reserved4);
|
||||||
LittleEndian.putUShort(data, 8 + offset, field_3_reserved4);
|
out.writeShort(field_4_reserved5);
|
||||||
LittleEndian.putUShort(data, 10 + offset, field_4_reserved5);
|
out.writeShort(field_5_reserved6);
|
||||||
LittleEndian.putUShort(data, 12 + offset, field_5_reserved6);
|
out.writeShort(_text.length());
|
||||||
LittleEndian.putUShort(data, 14 + offset, _text.length());
|
out.writeShort(getFormattingDataLength());
|
||||||
LittleEndian.putUShort(data, 16 + offset, getFormattingDataLength());
|
out.writeInt(field_8_reserved7);
|
||||||
LittleEndian.putInt(data, 18 + offset, field_8_reserved7);
|
|
||||||
|
|
||||||
if (_linkRefPtg != null) {
|
if (_linkRefPtg != null) {
|
||||||
int pos = offset+22;
|
|
||||||
int formulaSize = _linkRefPtg.getSize();
|
int formulaSize = _linkRefPtg.getSize();
|
||||||
LittleEndian.putUShort(data, pos, formulaSize);
|
out.writeShort(formulaSize);
|
||||||
pos += LittleEndian.SHORT_SIZE;
|
out.writeInt(_unknownPreFormulaInt);
|
||||||
LittleEndian.putInt(data, pos, _unknownPreFormulaInt);
|
_linkRefPtg.write(out);
|
||||||
pos += LittleEndian.INT_SIZE;
|
|
||||||
_linkRefPtg.writeBytes(data, pos);
|
|
||||||
pos += formulaSize;
|
|
||||||
if (_unknownPostFormulaByte != null) {
|
if (_unknownPostFormulaByte != null) {
|
||||||
LittleEndian.putByte(data, pos, _unknownPostFormulaByte.byteValue());
|
out.writeByte(_unknownPostFormulaByte.byteValue());
|
||||||
pos += LittleEndian.BYTE_SIZE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return recSize;
|
||||||
return 4 + dataSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int serializeTrailingRecords(int offset, byte[] data) {
|
private int serializeTrailingRecords(int offset, byte[] data) {
|
||||||
|
@ -36,13 +36,8 @@ import java.util.Collections;
|
|||||||
* @author Andrew C. Oliver
|
* @author Andrew C. Oliver
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
* @author Marc Johnson (mjohnson at apache dot org)
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
* @version 2.0-pre
|
|
||||||
*/
|
*/
|
||||||
|
public final class UnicodeString implements Comparable {
|
||||||
public class UnicodeString
|
|
||||||
implements Comparable
|
|
||||||
{
|
|
||||||
public final static short sid = 0xFFF;
|
|
||||||
private short field_1_charCount; // = 0;
|
private short field_1_charCount; // = 0;
|
||||||
private byte field_2_optionflags; // = 0;
|
private byte field_2_optionflags; // = 0;
|
||||||
private String field_3_string; // = null;
|
private String field_3_string; // = null;
|
||||||
@ -53,8 +48,8 @@ public class UnicodeString
|
|||||||
private static final BitField richText = BitFieldFactory.getInstance(0x8);
|
private static final BitField richText = BitFieldFactory.getInstance(0x8);
|
||||||
|
|
||||||
public static class FormatRun implements Comparable {
|
public static class FormatRun implements Comparable {
|
||||||
private short character;
|
short character;
|
||||||
private short fontIndex;
|
short fontIndex;
|
||||||
|
|
||||||
public FormatRun(short character, short fontIndex) {
|
public FormatRun(short character, short fontIndex) {
|
||||||
this.character = character;
|
this.character = character;
|
||||||
@ -102,15 +97,6 @@ public class UnicodeString
|
|||||||
setString(str);
|
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()
|
public int hashCode()
|
||||||
@ -142,9 +128,9 @@ public class UnicodeString
|
|||||||
&& field_3_string.equals(other.field_3_string));
|
&& field_3_string.equals(other.field_3_string));
|
||||||
if (!eq) return false;
|
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))
|
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;
|
return true;
|
||||||
if (((field_4_format_runs == null) && (other.field_4_format_runs != null)) ||
|
if (((field_4_format_runs == null) && (other.field_4_format_runs != null)) ||
|
||||||
(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
|
* @param in the RecordInputstream to read the record from
|
||||||
*/
|
*/
|
||||||
protected void fillFields(RecordInputStream in)
|
public UnicodeString(RecordInputStream in) {
|
||||||
{
|
|
||||||
field_1_charCount = in.readShort();
|
field_1_charCount = in.readShort();
|
||||||
field_2_optionflags = in.readByte();
|
field_2_optionflags = in.readByte();
|
||||||
|
|
||||||
@ -206,34 +192,12 @@ public class UnicodeString
|
|||||||
extensionLength = in.readInt();
|
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);
|
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) {
|
if (isCompressed) {
|
||||||
char ch = (char)in.readUByte(); // avoid sex
|
field_3_string = in.readCompressedUnicode(field_1_charCount);
|
||||||
tmpString.append(ch);
|
|
||||||
} else {
|
} else {
|
||||||
char ch = (char) in.readShort();
|
field_3_string = in.readUnicodeLEString(field_1_charCount);
|
||||||
tmpString.append(ch);
|
|
||||||
}
|
}
|
||||||
stringCharCount --;
|
|
||||||
}
|
|
||||||
field_3_string = tmpString.toString();
|
|
||||||
//Turn back on autocontinuation
|
|
||||||
in.setAutoContinue(true);
|
|
||||||
|
|
||||||
|
|
||||||
if (isRichText() && (runCount > 0)) {
|
if (isRichText() && (runCount > 0)) {
|
||||||
@ -305,13 +269,8 @@ public class UnicodeString
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the actual string this contains as a java String object
|
* @return the actual string this contains as a java String object
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return String
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public String getString()
|
public String getString()
|
||||||
{
|
{
|
||||||
return field_3_string;
|
return field_3_string;
|
||||||
@ -341,7 +300,7 @@ public class UnicodeString
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (useUTF16)
|
if (useUTF16)
|
||||||
//Set the uncomressed bit
|
//Set the uncompressed bit
|
||||||
field_2_optionflags = highByte.setByte(field_2_optionflags);
|
field_2_optionflags = highByte.setByte(field_2_optionflags);
|
||||||
else field_2_optionflags = highByte.clearByte(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);
|
LittleEndian.putShort(data, offset, ContinueRecord.sid);
|
||||||
offset+=2;
|
offset+=2;
|
||||||
//Record the location of the last continue legnth position, but dont write
|
//Record the location of the last continue length position, but don't write
|
||||||
//anything there yet (since we dont know what it will be!)
|
//anything there yet (since we don't know what it will be!)
|
||||||
stats.lastLengthPos = offset;
|
stats.lastLengthPos = offset;
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|
||||||
@ -514,7 +473,6 @@ public class UnicodeString
|
|||||||
|
|
||||||
//Basic string overhead
|
//Basic string overhead
|
||||||
pos = writeContinueIfRequired(stats, 3, pos, data);
|
pos = writeContinueIfRequired(stats, 3, pos, data);
|
||||||
// byte[] retval = new byte[ 3 + (getString().length() * charsize)];
|
|
||||||
LittleEndian.putShort(data, pos, getCharCount());
|
LittleEndian.putShort(data, pos, getCharCount());
|
||||||
pos += 2;
|
pos += 2;
|
||||||
data[ pos ] = getOptionFlags();
|
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
|
//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.
|
//the byte to start with that represents the first byte of the continue record.
|
||||||
if (strSize > stats.remainingSize) {
|
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
|
//we need an extra byte after the continue record ie we didnt finish
|
||||||
//writing out the string the 1st time through
|
//writing out the string the 1st time through
|
||||||
|
|
||||||
//But hang on, how many continue records did we span? What if this is
|
//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.
|
//a REALLY long string. We need to work this all out.
|
||||||
int ammountThatCantFit = strSize;
|
int amountThatCantFit = strSize;
|
||||||
int strPos = 0;
|
int strPos = 0;
|
||||||
while (ammountThatCantFit > 0) {
|
while (amountThatCantFit > 0) {
|
||||||
int ammountWritten = Math.min(stats.remainingSize, ammountThatCantFit);
|
int amountWritten = Math.min(stats.remainingSize, amountThatCantFit);
|
||||||
//Make sure that the ammount that cant fit takes into account
|
//Make sure that the amount that can't fit takes into account
|
||||||
//whether we are writing double byte unicode
|
//whether we are writing double byte unicode
|
||||||
if (isUncompressedUnicode()) {
|
if (isUncompressedUnicode()) {
|
||||||
//We have the '-1' here because whether this is the first record or
|
//We have the '-1' here because whether this is the first record or
|
||||||
//subsequent continue records, there is always the case that the
|
//subsequent continue records, there is always the case that the
|
||||||
//number of bytes in a string on doube byte boundaries is actually odd.
|
//number of bytes in a string on double byte boundaries is actually odd.
|
||||||
if ( ( (ammountWritten ) % 2) == 1)
|
if ( ( (amountWritten ) % 2) == 1)
|
||||||
ammountWritten--;
|
amountWritten--;
|
||||||
}
|
}
|
||||||
System.arraycopy(strBytes, strPos, data, pos, ammountWritten);
|
System.arraycopy(strBytes, strPos, data, pos, amountWritten);
|
||||||
pos += ammountWritten;
|
pos += amountWritten;
|
||||||
strPos += ammountWritten;
|
strPos += amountWritten;
|
||||||
stats.recordSize += ammountWritten;
|
stats.recordSize += amountWritten;
|
||||||
stats.remainingSize -= ammountWritten;
|
stats.remainingSize -= amountWritten;
|
||||||
|
|
||||||
//Ok lets subtract what we can write
|
//Ok lets subtract what we can write
|
||||||
ammountThatCantFit -= ammountWritten;
|
amountThatCantFit -= amountWritten;
|
||||||
|
|
||||||
//Each iteration of this while loop is another continue record, unless
|
//Each iteration of this while loop is another continue record, unless
|
||||||
//everything now fits.
|
//everything now fits.
|
||||||
if (ammountThatCantFit > 0) {
|
if (amountThatCantFit > 0) {
|
||||||
//We know that a continue WILL be requied, but use this common method
|
//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
|
//The first byte after a continue mid string is the extra byte to
|
||||||
//indicate if this run is compressed or not.
|
//indicate if this run is compressed or not.
|
||||||
@ -686,7 +644,7 @@ public class UnicodeString
|
|||||||
return highByte.isSet(getOptionFlags());
|
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.
|
* 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)
|
public int compareTo(Object obj)
|
||||||
{
|
{
|
||||||
UnicodeString str = ( UnicodeString ) 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
|
//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))
|
if ((field_5_ext_rst == null) && (str.field_5_ext_rst == null))
|
||||||
return 0;
|
return 0;
|
||||||
if ((field_5_ext_rst == null) && (str.field_5_ext_rst != null))
|
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
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,110 +15,129 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title: Write Access Record<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
|
* Description: Stores the username of that who owns the spreadsheet generator (on unix the user's
|
||||||
* you installed the thing)<P>
|
* login, on Windoze its the name you typed when you installed the thing)
|
||||||
* REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
* <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)
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||||
* @version 2.0-pre
|
|
||||||
*/
|
*/
|
||||||
|
public final class WriteAccessRecord extends Record {
|
||||||
public class WriteAccessRecord
|
private static final byte PAD_CHAR = (byte) ' ';
|
||||||
extends Record
|
public final static short sid = 0x005C;
|
||||||
{
|
private static final int DATA_SIZE = 112;
|
||||||
public final static short sid = 0x5c;
|
|
||||||
private String field_1_username;
|
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)
|
public WriteAccessRecord(RecordInputStream in) {
|
||||||
{
|
if (in.remaining() > DATA_SIZE) {
|
||||||
byte[] data = in.readRemainder();
|
throw new RecordFormatException("Expected data size (" + DATA_SIZE + ") but got ("
|
||||||
//The string is always 112 characters (padded with spaces), therefore
|
+ in.remaining() + ")");
|
||||||
//this record can not be continued.
|
}
|
||||||
|
// 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
|
int nChars = in.readUShort();
|
||||||
//header doesnt provide a correct size indication.???
|
int is16BitFlag = in.readUByte();
|
||||||
//But the header is present, so we need to skip over it.
|
int expectedPadSize = DATA_SIZE - 3;
|
||||||
//Odd, Odd, Odd ;-)
|
if ((is16BitFlag & 0x01) == 0x00) {
|
||||||
field_1_username = StringUtil.getFromCompressedUnicode(data, 3, data.length - 3);
|
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")
|
* @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;
|
field_1_username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the username for the user that created the report. HSSF uses the logged in user. On
|
* get the username for the user that created the report. HSSF uses the
|
||||||
* natively created M$ Excel sheet this would be the name you typed in when you installed it
|
* logged in user. On natively created M$ Excel sheet this would be the name
|
||||||
* in most cases.
|
* you typed in when you installed it in most cases.
|
||||||
|
*
|
||||||
* @return username of the user who is logged in (probably "tomcat" or "apache")
|
* @return username of the user who is logged in (probably "tomcat" or "apache")
|
||||||
*/
|
*/
|
||||||
|
public String getUsername() {
|
||||||
public String getUsername()
|
|
||||||
{
|
|
||||||
return field_1_username;
|
return field_1_username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString() {
|
||||||
{
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
buffer.append("[WRITEACCESS]\n");
|
buffer.append("[WRITEACCESS]\n");
|
||||||
buffer.append(" .name = ")
|
buffer.append(" .name = ").append(field_1_username.toString()).append("\n");
|
||||||
.append(field_1_username.toString()).append("\n");
|
|
||||||
buffer.append("[/WRITEACCESS]\n");
|
buffer.append("[/WRITEACCESS]\n");
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int serialize(int offset, byte [] data)
|
public int serialize(int offset, byte[] data) {
|
||||||
{
|
|
||||||
String username = getUsername();
|
String username = getUsername();
|
||||||
StringBuffer temp = new StringBuffer(0x70 - (0x3));
|
boolean is16bit = StringUtil.hasMultibyte(username);
|
||||||
|
|
||||||
temp.append(username);
|
LittleEndian.putUShort(data, 0 + offset, sid);
|
||||||
while (temp.length() < 0x70 - 0x3)
|
LittleEndian.putUShort(data, 2 + offset, DATA_SIZE);
|
||||||
{
|
LittleEndian.putUShort(data, 4 + offset, username.length());
|
||||||
temp.append(
|
LittleEndian.putByte(data, 6 + offset, is16bit ? 0x01 : 0x00);
|
||||||
" "); // (70 = fixed lenght -3 = the overhead bits of unicode string)
|
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();
|
System.arraycopy(padding, 0, data, pos, padding.length);
|
||||||
UnicodeString str = new UnicodeString(username);
|
return 4 + DATA_SIZE;
|
||||||
str.setOptionFlags(( byte ) 0x0);
|
|
||||||
|
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
|
||||||
LittleEndian.putShort(data, 2 + offset, (short)112); // 112 bytes (115 total)
|
|
||||||
UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats();
|
|
||||||
stats.recordSize += 4;
|
|
||||||
stats.remainingSize-= 4;
|
|
||||||
str.serialize(stats, 4 + offset, data);
|
|
||||||
|
|
||||||
return getRecordSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRecordSize()
|
public int getRecordSize() {
|
||||||
{
|
return 4 + DATA_SIZE;
|
||||||
return 116;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid()
|
public short getSid() {
|
||||||
{
|
|
||||||
return sid;
|
return sid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.constant;
|
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;
|
||||||
import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
|
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.
|
* 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
|
// 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];
|
Object[] result = new Object[nValues];
|
||||||
for (int i = 0; i < result.length; i++) {
|
for (int i = 0; i < result.length; i++) {
|
||||||
result[i] = readAConstantValue(in);
|
result[i] = readAConstantValue(in);
|
||||||
@ -55,7 +56,7 @@ public final class ConstantValueParser {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object readAConstantValue(RecordInputStream in) {
|
private static Object readAConstantValue(LittleEndianInput in) {
|
||||||
byte grbit = in.readByte();
|
byte grbit = in.readByte();
|
||||||
switch(grbit) {
|
switch(grbit) {
|
||||||
case TYPE_EMPTY:
|
case TYPE_EMPTY:
|
||||||
@ -64,7 +65,7 @@ public final class ConstantValueParser {
|
|||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
return new Double(in.readDouble());
|
return new Double(in.readDouble());
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
return in.readUnicodeString();
|
return new UnicodeString(StringUtil.readUnicodeString(in));
|
||||||
case TYPE_BOOLEAN:
|
case TYPE_BOOLEAN:
|
||||||
return readBoolean(in);
|
return readBoolean(in);
|
||||||
case TYPE_ERROR_CODE:
|
case TYPE_ERROR_CODE:
|
||||||
@ -77,7 +78,7 @@ public final class ConstantValueParser {
|
|||||||
throw new RuntimeException("Unknown grbit value (" + grbit + ")");
|
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'
|
byte val = (byte)in.readLong(); // 7 bytes 'not used'
|
||||||
switch(val) {
|
switch(val) {
|
||||||
case FALSE_ENCODING:
|
case FALSE_ENCODING:
|
||||||
@ -116,46 +117,43 @@ public final class ConstantValueParser {
|
|||||||
return urs.recordSize;
|
return urs.recordSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void encode(byte[] data, int offset, Object[] values) {
|
public static void encode(LittleEndianOutput out, Object[] values) {
|
||||||
int currentOffset = offset;
|
|
||||||
for (int i = 0; i < values.length; i++) {
|
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) {
|
if (value == EMPTY_REPRESENTATION) {
|
||||||
LittleEndian.putByte(data, offset, TYPE_EMPTY);
|
out.writeByte(TYPE_EMPTY);
|
||||||
LittleEndian.putLong(data, offset+1, 0L);
|
out.writeLong(0L);
|
||||||
return 9;
|
return;
|
||||||
}
|
}
|
||||||
if (value instanceof Boolean) {
|
if (value instanceof Boolean) {
|
||||||
Boolean bVal = ((Boolean)value);
|
Boolean bVal = ((Boolean)value);
|
||||||
LittleEndian.putByte(data, offset, TYPE_BOOLEAN);
|
out.writeByte(TYPE_BOOLEAN);
|
||||||
long longVal = bVal.booleanValue() ? 1L : 0L;
|
long longVal = bVal.booleanValue() ? 1L : 0L;
|
||||||
LittleEndian.putLong(data, offset+1, longVal);
|
out.writeLong(longVal);
|
||||||
return 9;
|
return;
|
||||||
}
|
}
|
||||||
if (value instanceof Double) {
|
if (value instanceof Double) {
|
||||||
Double dVal = (Double) value;
|
Double dVal = (Double) value;
|
||||||
LittleEndian.putByte(data, offset, TYPE_NUMBER);
|
out.writeByte(TYPE_NUMBER);
|
||||||
LittleEndian.putDouble(data, offset+1, dVal.doubleValue());
|
out.writeDouble(dVal.doubleValue());
|
||||||
return 9;
|
return;
|
||||||
}
|
}
|
||||||
if (value instanceof UnicodeString) {
|
if (value instanceof UnicodeString) {
|
||||||
UnicodeString usVal = (UnicodeString) value;
|
UnicodeString usVal = (UnicodeString) value;
|
||||||
LittleEndian.putByte(data, offset, TYPE_STRING);
|
out.writeByte(TYPE_STRING);
|
||||||
UnicodeRecordStats urs = new UnicodeRecordStats();
|
StringUtil.writeUnicodeString(out, usVal.getString());
|
||||||
usVal.serialize(urs, offset +1, data);
|
return;
|
||||||
return 1 + urs.recordSize;
|
|
||||||
}
|
}
|
||||||
if (value instanceof ErrorConstant) {
|
if (value instanceof ErrorConstant) {
|
||||||
ErrorConstant ecVal = (ErrorConstant) value;
|
ErrorConstant ecVal = (ErrorConstant) value;
|
||||||
LittleEndian.putByte(data, offset, TYPE_ERROR_CODE);
|
out.writeByte(TYPE_ERROR_CODE);
|
||||||
LittleEndian.putUShort(data, offset+1, ecVal.getErrorCode());
|
long longVal = ecVal.getErrorCode();
|
||||||
LittleEndian.putUShort(data, offset+3, 0);
|
out.writeLong(longVal);
|
||||||
LittleEndian.putInt(data, offset+5, 0);
|
return;
|
||||||
return 9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalStateException("Unexpected value type (" + value.getClass().getName() + "'");
|
throw new IllegalStateException("Unexpected value type (" + value.getClass().getName() + "'");
|
||||||
|
@ -98,7 +98,6 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
|
|||||||
buf.append(")");
|
buf.append(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void writeBytes(byte[] array, int offset);
|
|
||||||
public abstract int getSize();
|
public abstract int getSize();
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common superclass of 2-D area refs
|
* 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) {
|
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);
|
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
|
||||||
}
|
}
|
||||||
protected Area2DPtgBase(RecordInputStream in) {
|
|
||||||
|
protected Area2DPtgBase(LittleEndianInput in) {
|
||||||
readCoordinates(in);
|
readCoordinates(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract byte getSid();
|
protected abstract byte getSid();
|
||||||
|
|
||||||
public final void writeBytes(byte [] array, int offset) {
|
public final void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
|
out.writeByte(getSid() + getPtgClass());
|
||||||
writeCoordinates(array, offset+1);
|
writeCoordinates(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Area2DPtgBase(String arearef) {
|
public Area2DPtgBase(String arearef) {
|
||||||
super(arearef);
|
super(arearef);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getSize() {
|
public final int getSize() {
|
||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String toFormulaString() {
|
public final String toFormulaString() {
|
||||||
return formatReferenceAsString();
|
return formatReferenceAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append(getClass().getName());
|
sb.append(getClass().getName());
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.ExternSheetReferenceToken;
|
||||||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
||||||
import org.apache.poi.ss.formula.WorkbookDependentFormula;
|
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>
|
* Title: Area 3D Ptg - 3D reference (Sheet + Area)<P>
|
||||||
@ -44,7 +44,7 @@ public final class Area3DPtg extends AreaPtgBase implements WorkbookDependentFor
|
|||||||
setExternSheetIndex( externIdx );
|
setExternSheetIndex( externIdx );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Area3DPtg(RecordInputStream in) {
|
public Area3DPtg(LittleEndianInput in) {
|
||||||
field_1_index_extern_sheet = in.readShort();
|
field_1_index_extern_sheet = in.readShort();
|
||||||
readCoordinates(in);
|
readCoordinates(in);
|
||||||
}
|
}
|
||||||
@ -67,10 +67,10 @@ public final class Area3DPtg extends AreaPtgBase implements WorkbookDependentFor
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(array, 1 + offset, field_1_index_extern_sheet);
|
out.writeShort(field_1_index_extern_sheet);
|
||||||
writeCoordinates(array, offset+3);
|
writeCoordinates(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.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.
|
* AreaErr - handles deleted cell area references.
|
||||||
@ -36,16 +36,16 @@ public final class AreaErrPtg extends OperandPtg {
|
|||||||
unused2 = 0;
|
unused2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AreaErrPtg(RecordInputStream in) {
|
public AreaErrPtg(LittleEndianInput in) {
|
||||||
// 8 bytes unused:
|
// 8 bytes unused:
|
||||||
unused1 = in.readInt();
|
unused1 = in.readInt();
|
||||||
unused2 = in.readInt();
|
unused2 = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putInt(array, offset + 1, unused1);
|
out.writeInt(unused1);
|
||||||
LittleEndian.putInt(array, offset + 5, unused2);
|
out.writeInt(unused2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString() {
|
public String toFormulaString() {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.
|
* 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 class AreaNPtg extends Area2DPtgBase {
|
||||||
public final static short sid = 0x2D;
|
public final static short sid = 0x2D;
|
||||||
|
|
||||||
public AreaNPtg(RecordInputStream in) {
|
public AreaNPtg(LittleEndianInput in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.
|
* 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) {
|
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);
|
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
|
||||||
}
|
}
|
||||||
public AreaPtg(RecordInputStream in) {
|
public AreaPtg(LittleEndianInput in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
public AreaPtg(String arearef) {
|
public AreaPtg(String arearef) {
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.AreaReference;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.util.BitField;
|
import org.apache.poi.util.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
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.
|
* 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_1_first_row = in.readUShort();
|
||||||
field_2_last_row = in.readUShort();
|
field_2_last_row = in.readUShort();
|
||||||
field_3_first_column = in.readUShort();
|
field_3_first_column = in.readUShort();
|
||||||
field_4_last_column = in.readUShort();
|
field_4_last_column = in.readUShort();
|
||||||
}
|
}
|
||||||
protected final void writeCoordinates(byte[] array, int offset) {
|
protected final void writeCoordinates(LittleEndianOutput out) {
|
||||||
LittleEndian.putUShort(array, offset + 0, field_1_first_row);
|
out.writeShort(field_1_first_row);
|
||||||
LittleEndian.putUShort(array, offset + 2, field_2_last_row);
|
out.writeShort(field_2_last_row);
|
||||||
LittleEndian.putUShort(array, offset + 4, field_3_first_column);
|
out.writeShort(field_3_first_column);
|
||||||
LittleEndian.putUShort(array, offset + 6, field_4_last_column);
|
out.writeShort(field_4_last_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.UnicodeString;
|
||||||
import org.apache.poi.hssf.record.constant.ConstantValueParser;
|
import org.apache.poi.hssf.record.constant.ConstantValueParser;
|
||||||
import org.apache.poi.hssf.record.constant.ErrorConstant;
|
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
|
* ArrayPtg - handles arrays
|
||||||
@ -54,7 +54,7 @@ public final class ArrayPtg extends Ptg {
|
|||||||
private short token_2_rows;
|
private short token_2_rows;
|
||||||
private Object[] token_3_arrayValues;
|
private Object[] token_3_arrayValues;
|
||||||
|
|
||||||
public ArrayPtg(RecordInputStream in) {
|
public ArrayPtg(LittleEndianInput in) {
|
||||||
field_1_reserved = new byte[RESERVED_FIELD_LEN];
|
field_1_reserved = new byte[RESERVED_FIELD_LEN];
|
||||||
// TODO - add readFully method to RecordInputStream
|
// TODO - add readFully method to RecordInputStream
|
||||||
for(int i=0; i< RESERVED_FIELD_LEN; i++) {
|
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.
|
* AFTER the last Ptg in the expression.
|
||||||
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
|
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
|
||||||
*/
|
*/
|
||||||
public void readTokenValues(RecordInputStream in) {
|
public void readTokenValues(LittleEndianInput in) {
|
||||||
int nColumns = in.readUByte();
|
int nColumns = in.readUByte();
|
||||||
short nRows = in.readShort();
|
short nRows = in.readShort();
|
||||||
//The token_1_columns and token_2_rows do not follow the documentation.
|
//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) {
|
if (token_3_arrayValues == null) {
|
||||||
sb.append(" #values#uninitialised#\n");
|
sb.append(" #values#uninitialised#\n");
|
||||||
} else {
|
} else {
|
||||||
sb.append(" ").append(formatAsString());
|
sb.append(" ").append(toFormulaString());
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
@ -153,17 +153,16 @@ public final class ArrayPtg extends Ptg {
|
|||||||
return rowIx * token_1_columns + colIx;
|
return rowIx * token_1_columns + colIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] data, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putByte(data, offset + 0, sid + getPtgClass());
|
out.write(field_1_reserved);
|
||||||
System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int writeTokenValueBytes(byte[] data, int offset) {
|
public int writeTokenValueBytes(LittleEndianOutput out) {
|
||||||
|
|
||||||
LittleEndian.putByte(data, offset + 0, token_1_columns-1);
|
out.writeByte(token_1_columns-1);
|
||||||
LittleEndian.putUShort(data, offset + 1, token_2_rows-1);
|
out.writeShort(token_2_rows-1);
|
||||||
ConstantValueParser.encode(data, offset + 3, token_3_arrayValues);
|
ConstantValueParser.encode(out, token_3_arrayValues);
|
||||||
return 3 + ConstantValueParser.getEncodedSize(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);
|
+ ConstantValueParser.getEncodedSize(token_3_arrayValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String formatAsString() { // TODO - fold into toFormulaString
|
public String toFormulaString() {
|
||||||
StringBuffer b = new StringBuffer();
|
StringBuffer b = new StringBuffer();
|
||||||
b.append("{");
|
b.append("{");
|
||||||
for (int y=0;y<getRowCount();y++) {
|
for (int y=0;y<getRowCount();y++) {
|
||||||
@ -201,9 +200,6 @@ public final class ArrayPtg extends Ptg {
|
|||||||
b.append("}");
|
b.append("}");
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
public String toFormulaString() {
|
|
||||||
return formatAsString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getConstantText(Object o) {
|
private static String getConstantText(Object o) {
|
||||||
|
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Special Attributes"
|
* "Special Attributes"
|
||||||
@ -78,7 +79,7 @@ public final class AttrPtg extends ControlPtg {
|
|||||||
_chooseFuncOffset = -1;
|
_chooseFuncOffset = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttrPtg(RecordInputStream in)
|
public AttrPtg(LittleEndianInput in)
|
||||||
{
|
{
|
||||||
field_1_options = in.readByte();
|
field_1_options = in.readByte();
|
||||||
field_2_data = in.readShort();
|
field_2_data = in.readShort();
|
||||||
@ -213,19 +214,16 @@ public final class AttrPtg extends ControlPtg {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putByte(array, offset+0, sid);
|
out.writeByte(field_1_options);
|
||||||
LittleEndian.putByte(array, offset+1, field_1_options);
|
out.writeShort(field_2_data);
|
||||||
LittleEndian.putShort(array,offset+2, field_2_data);
|
|
||||||
int[] jt = _jumpTable;
|
int[] jt = _jumpTable;
|
||||||
if (jt != null) {
|
if (jt != null) {
|
||||||
int joff = offset+4;
|
|
||||||
for (int i = 0; i < jt.length; i++) {
|
for (int i = 0; i < jt.length; i++) {
|
||||||
LittleEndian.putUShort(array, joff, jt[i]);
|
out.writeShort(jt[i]);
|
||||||
joff+=2;
|
|
||||||
}
|
}
|
||||||
LittleEndian.putUShort(array, joff, _chooseFuncOffset);
|
out.writeShort(_chooseFuncOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,21 +17,22 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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)
|
* Boolean (boolean) Stores a (java) boolean value in a formula.
|
||||||
* Stores a (java) boolean value in a formula.
|
*
|
||||||
* @author Paul Krause (pkrause at soundbite dot com)
|
* @author Paul Krause (pkrause at soundbite dot com)
|
||||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public final class BoolPtg extends ScalarConstantPtg {
|
public final class BoolPtg extends ScalarConstantPtg {
|
||||||
public final static int SIZE = 2;
|
public final static int SIZE = 2;
|
||||||
public final static byte sid = 0x1d;
|
public final static byte sid = 0x1D;
|
||||||
private final boolean _value;
|
private final boolean _value;
|
||||||
|
|
||||||
public BoolPtg(RecordInputStream in) {
|
public BoolPtg(LittleEndianInput in) {
|
||||||
_value = (in.readByte() == 1);
|
_value = (in.readByte() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +44,9 @@ public final class BoolPtg extends ScalarConstantPtg {
|
|||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[ offset + 0 ] = sid;
|
out.writeByte(sid + getPtgClass());
|
||||||
array[ offset + 1 ] = (byte) (_value ? 1 : 0);
|
out.writeByte(_value ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.HSSFErrorConstants;
|
||||||
import org.apache.poi.ss.formula.WorkbookDependentFormula;
|
|
||||||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
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>
|
* Title: Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
|
||||||
@ -42,7 +42,7 @@ public final class DeletedArea3DPtg extends OperandPtg implements WorkbookDepend
|
|||||||
unused2 = 0;
|
unused2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeletedArea3DPtg(RecordInputStream in) {
|
public DeletedArea3DPtg(LittleEndianInput in) {
|
||||||
field_1_index_extern_sheet = in.readUShort();
|
field_1_index_extern_sheet = in.readUShort();
|
||||||
unused1 = in.readInt();
|
unused1 = in.readInt();
|
||||||
unused2 = in.readInt();
|
unused2 = in.readInt();
|
||||||
@ -60,10 +60,10 @@ public final class DeletedArea3DPtg extends OperandPtg implements WorkbookDepend
|
|||||||
public int getSize() {
|
public int getSize() {
|
||||||
return 11;
|
return 11;
|
||||||
}
|
}
|
||||||
public void writeBytes(byte[] data, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
|
out.writeShort(field_1_index_extern_sheet);
|
||||||
LittleEndian.putInt(data, 3 + offset, unused1);
|
out.writeInt(unused1);
|
||||||
LittleEndian.putInt(data, 7 + offset, unused2);
|
out.writeInt(unused2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
package org.apache.poi.hssf.record.formula;
|
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.HSSFErrorConstants;
|
||||||
import org.apache.poi.ss.formula.WorkbookDependentFormula;
|
|
||||||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
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>
|
* Title: Deleted Reference 3D Ptg <P>
|
||||||
@ -37,7 +37,7 @@ public final class DeletedRef3DPtg extends OperandPtg implements WorkbookDepende
|
|||||||
private final int unused1;
|
private final int unused1;
|
||||||
|
|
||||||
/** Creates new DeletedRef3DPtg */
|
/** Creates new DeletedRef3DPtg */
|
||||||
public DeletedRef3DPtg(RecordInputStream in) {
|
public DeletedRef3DPtg(LittleEndianInput in) {
|
||||||
field_1_index_extern_sheet = in.readUShort();
|
field_1_index_extern_sheet = in.readUShort();
|
||||||
unused1 = in.readInt();
|
unused1 = in.readInt();
|
||||||
}
|
}
|
||||||
@ -60,9 +60,9 @@ public final class DeletedRef3DPtg extends OperandPtg implements WorkbookDepende
|
|||||||
public int getSize() {
|
public int getSize() {
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
public void writeBytes(byte[] data, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
|
out.writeShort(field_1_index_extern_sheet);
|
||||||
LittleEndian.putInt(data, 3 + offset, unused1);
|
out.writeInt(unused1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.HSSFErrorConstants;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
* @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;
|
field_1_error_code = errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ErrPtg read(RecordInputStream in) {
|
public static ErrPtg read(LittleEndianInput in) {
|
||||||
return valueOf(in.readByte());
|
return valueOf(in.readByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[offset] = (byte) (sid + getPtgClass());
|
out.writeByte(field_1_error_code);
|
||||||
array[offset + 1] = (byte)field_1_error_code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString() {
|
public String toFormulaString() {
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordFormatException;
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.util.LittleEndian;
|
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_1_first_row;
|
||||||
private final short field_2_first_col;
|
private final short field_2_first_col;
|
||||||
|
|
||||||
public ExpPtg(RecordInputStream in)
|
public ExpPtg(LittleEndianInput in)
|
||||||
{
|
{
|
||||||
field_1_first_row = in.readShort();
|
field_1_first_row = in.readShort();
|
||||||
field_2_first_col = in.readShort();
|
field_2_first_col = in.readShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[offset+0]= (byte) (sid);
|
out.writeShort(field_1_first_row);
|
||||||
LittleEndian.putShort(array,offset+1,field_1_first_row);
|
out.writeShort(field_2_first_col);
|
||||||
LittleEndian.putShort(array,offset+3,field_2_first_col);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize()
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.FunctionMetadata;
|
||||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author aviks
|
* @author aviks
|
||||||
@ -35,7 +35,7 @@ public final class FuncPtg extends AbstractFunctionPtg {
|
|||||||
/**Creates new function pointer from a byte array
|
/**Creates new function pointer from a byte array
|
||||||
* usually called while reading an excel file.
|
* usually called while reading an excel file.
|
||||||
*/
|
*/
|
||||||
public FuncPtg(RecordInputStream in) {
|
public FuncPtg(LittleEndianInput in) {
|
||||||
//field_1_num_args = data[ offset + 0 ];
|
//field_1_num_args = data[ offset + 0 ];
|
||||||
field_2_fnc_index = in.readShort();
|
field_2_fnc_index = in.readShort();
|
||||||
|
|
||||||
@ -55,9 +55,9 @@ public final class FuncPtg extends AbstractFunctionPtg {
|
|||||||
paramClass = fm.getParameterClassCodes();
|
paramClass = fm.getParameterClassCodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[offset+0]= (byte) (sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putShort(array,offset+1,field_2_fnc_index);
|
out.writeShort(field_2_fnc_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfOperands() {
|
public int getNumberOfOperands() {
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.FunctionMetadata;
|
||||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
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
|
/**Creates new function pointer from a byte array
|
||||||
* usually called while reading an excel file.
|
* usually called while reading an excel file.
|
||||||
*/
|
*/
|
||||||
public FuncVarPtg(RecordInputStream in) {
|
public FuncVarPtg(LittleEndianInput in) {
|
||||||
field_1_num_args = in.readByte();
|
field_1_num_args = in.readByte();
|
||||||
field_2_fnc_index = in.readShort();
|
field_2_fnc_index = in.readShort();
|
||||||
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(field_2_fnc_index);
|
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) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[offset+0]=(byte) (sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
array[offset+1]=field_1_num_args;
|
out.writeByte(field_1_num_args);
|
||||||
LittleEndian.putShort(array,offset+2,field_2_fnc_index);
|
out.writeShort(field_2_fnc_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfOperands() {
|
public int getNumberOfOperands() {
|
||||||
|
@ -17,12 +17,13 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integer (unsigned short integer)
|
* Integer (unsigned short integer) Stores an unsigned short value (java int) in
|
||||||
* Stores an unsigned short value (java int) in a formula
|
* a formula
|
||||||
|
*
|
||||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @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.
|
* Excel represents integers 0..65535 with the tInt token.
|
||||||
|
*
|
||||||
* @return <code>true</code> if the specified value is within the range of values
|
* @return <code>true</code> if the specified value is within the range of values
|
||||||
* <tt>IntPtg</tt> can represent.
|
* <tt>IntPtg</tt> can represent.
|
||||||
*/
|
*/
|
||||||
public static boolean isInRange(int i) {
|
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 int SIZE = 3;
|
||||||
public final static byte sid = 0x1e;
|
public final static byte sid = 0x1e;
|
||||||
private final int field_1_value;
|
private final int field_1_value;
|
||||||
|
|
||||||
public IntPtg(RecordInputStream in) {
|
public IntPtg(LittleEndianInput in) {
|
||||||
this(in.readUShort());
|
this(in.readUShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntPtg(int value) {
|
public IntPtg(int value) {
|
||||||
if(!isInRange(value)) {
|
if (!isInRange(value)) {
|
||||||
throw new IllegalArgumentException("value is out of range: " + value);
|
throw new IllegalArgumentException("value is out of range: " + value);
|
||||||
}
|
}
|
||||||
field_1_value = value;
|
field_1_value = value;
|
||||||
@ -59,9 +61,9 @@ public final class IntPtg extends ScalarConstantPtg {
|
|||||||
return field_1_value;
|
return field_1_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[ offset + 0 ] = sid;
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(array, offset + 1, getValue());
|
out.writeShort(getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
* @author Daniel Noll (daniel at nuix dot com dot au)
|
||||||
@ -34,37 +35,28 @@ public final class IntersectionPtg extends OperationPtg {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize() {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes( byte[] array, int offset )
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[ offset + 0 ] = sid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation of method from Ptg */
|
public String toFormulaString() {
|
||||||
public String toFormulaString()
|
|
||||||
{
|
|
||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toFormulaString(String[] operands) {
|
||||||
/** implementation of method from OperationsPtg*/
|
|
||||||
public String toFormulaString(String[] operands)
|
|
||||||
{
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
buffer.append(operands[ 0 ]);
|
buffer.append(operands[0]);
|
||||||
buffer.append(" ");
|
buffer.append(" ");
|
||||||
buffer.append(operands[ 1 ]);
|
buffer.append(operands[1]);
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfOperands()
|
public int getNumberOfOperands() {
|
||||||
{
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
* @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 class MemAreaPtg extends OperandPtg {
|
||||||
public final static short sid = 0x26;
|
public final static short sid = 0x26;
|
||||||
private final static int SIZE = 7;
|
private final static int SIZE = 7;
|
||||||
private int field_1_reserved;
|
private final int field_1_reserved;
|
||||||
private short field_2_subex_len;
|
private final int field_2_subex_len;
|
||||||
|
|
||||||
/** Creates new MemAreaPtg */
|
/** Creates new MemAreaPtg */
|
||||||
|
|
||||||
public MemAreaPtg()
|
public MemAreaPtg(int subexLen) {
|
||||||
{
|
field_1_reserved = 0;
|
||||||
|
field_2_subex_len = subexLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemAreaPtg(RecordInputStream in)
|
public MemAreaPtg(LittleEndianInput in) {
|
||||||
{
|
|
||||||
field_1_reserved = in.readInt();
|
field_1_reserved = in.readInt();
|
||||||
field_2_subex_len = in.readShort();
|
field_2_subex_len = in.readShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReserved(int res)
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
field_1_reserved = res;
|
out.writeInt(field_1_reserved);
|
||||||
|
out.writeShort(field_2_subex_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getReserved()
|
public int getSize() {
|
||||||
{
|
|
||||||
return field_1_reserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubexpressionLength(short subexlen)
|
|
||||||
{
|
|
||||||
field_2_subex_len = subexlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSubexpressionLength()
|
|
||||||
{
|
|
||||||
return field_2_subex_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
|
||||||
{
|
|
||||||
array[offset] = (byte) (sid + getPtgClass());
|
|
||||||
LittleEndian.putInt(array, offset + 1, field_1_reserved);
|
|
||||||
LittleEndian.putShort(array, offset + 5, field_2_subex_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSize()
|
|
||||||
{
|
|
||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString()
|
public String toFormulaString() {
|
||||||
{
|
|
||||||
return ""; // TODO: Not sure how to format this. -- DN
|
return ""; // TODO: Not sure how to format this. -- DN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
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 Jason Height (jheight at chariot dot net dot au)
|
||||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
* @author Daniel Noll (daniel at nuix dot com dot au)
|
||||||
*/
|
*/
|
||||||
|
public final class MemErrPtg extends OperandPtg {
|
||||||
public final class MemErrPtg extends MemAreaPtg {
|
|
||||||
public final static short sid = 0x27;
|
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(LittleEndianInput in) {
|
||||||
|
field_1_reserved = in.readInt();
|
||||||
public MemErrPtg()
|
field_2_subex_len = in.readShort();
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemErrPtg(RecordInputStream in) {
|
public void write(LittleEndianOutput out) {
|
||||||
super(in);
|
out.writeByte(sid + getPtgClass());
|
||||||
|
out.writeInt(field_1_reserved);
|
||||||
|
out.writeShort(field_2_subex_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public int getSize() {
|
||||||
super.writeBytes(array, offset);
|
return SIZE;
|
||||||
array[offset] = (byte) (sid + getPtgClass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString()
|
public String toFormulaString() {
|
||||||
{
|
|
||||||
return "ERR#";
|
return "ERR#";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getDefaultOperandClass() {
|
||||||
|
return Ptg.CLASS_VALUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
@ -28,10 +28,11 @@ public final class MemFuncPtg extends OperandPtg {
|
|||||||
public final static byte sid = 0x29;
|
public final static byte sid = 0x29;
|
||||||
private final int field_1_len_ref_subexpression;
|
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());
|
this(in.readUShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,34 +40,28 @@ public final class MemFuncPtg extends OperandPtg {
|
|||||||
field_1_len_ref_subexpression = subExprLen;
|
field_1_len_ref_subexpression = subExprLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize() {
|
||||||
{
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes( byte[] array, int offset )
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[offset + 0] = sid ;
|
out.writeShort(field_1_len_ref_subexpression);
|
||||||
LittleEndian.putUShort( array, offset + 1, field_1_len_ref_subexpression );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString()
|
public String toFormulaString() {
|
||||||
{
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getDefaultOperandClass()
|
public byte getDefaultOperandClass() {
|
||||||
{
|
|
||||||
return Ptg.CLASS_REF;
|
return Ptg.CLASS_REF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfOperands()
|
public int getNumberOfOperands() {
|
||||||
{
|
|
||||||
return field_1_len_ref_subexpression;
|
return field_1_len_ref_subexpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLenRefSubexpression()
|
public int getLenRefSubexpression() {
|
||||||
{
|
|
||||||
return field_1_len_ref_subexpression;
|
return field_1_len_ref_subexpression;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,10 +17,13 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Missing Function Arguments
|
* Missing Function Arguments
|
||||||
*
|
*
|
||||||
* Avik Sengupta <avik at apache.org>
|
* Avik Sengupta <avik at apache.org>
|
||||||
|
*
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public final class MissingArgPtg extends ScalarConstantPtg {
|
public final class MissingArgPtg extends ScalarConstantPtg {
|
||||||
@ -34,8 +37,8 @@ public final class MissingArgPtg extends ScalarConstantPtg {
|
|||||||
// enforce singleton
|
// enforce singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[ offset + 0 ] = sid;
|
out.writeByte(sid + getPtgClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.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
|
* @param nameIndex zero-based index to name within workbook
|
||||||
*/
|
*/
|
||||||
public NamePtg(int nameIndex) {
|
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 */
|
/** Creates new NamePtg */
|
||||||
|
|
||||||
public NamePtg(RecordInputStream in) {
|
public NamePtg(LittleEndianInput in) {
|
||||||
field_1_label_index = in.readShort();
|
field_1_label_index = in.readShort();
|
||||||
field_2_zero = 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
|
* @return zero based index to a defined name record in the LinkTable
|
||||||
*/
|
*/
|
||||||
public int getIndex() {
|
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) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(array, offset + 1, field_1_label_index);
|
out.writeShort(field_1_label_index);
|
||||||
LittleEndian.putUShort(array, offset + 3, field_2_zero);
|
out.writeShort(field_2_zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString(FormulaRenderingWorkbook book)
|
public String toFormulaString(FormulaRenderingWorkbook book) {
|
||||||
{
|
|
||||||
return book.getNameText(this);
|
return book.getNameText(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString() {
|
public String toFormulaString() {
|
||||||
throw new RuntimeException("3D references need a workbook to determine formula text");
|
throw new RuntimeException("3D references need a workbook to determine formula text");
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.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);
|
this(sheetRefIndex, nameIndex + 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NameXPtg(RecordInputStream in) {
|
public NameXPtg(LittleEndianInput in) {
|
||||||
this(in.readUShort(), in.readUShort(), in.readUShort());
|
this(in.readUShort(), in.readUShort(), in.readUShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(array, offset + 1, _sheetRefIndex);
|
out.writeShort(_sheetRefIndex);
|
||||||
LittleEndian.putUShort(array, offset + 3, _nameNumber);
|
out.writeShort(_nameNumber);
|
||||||
LittleEndian.putUShort(array, offset + 5, _reserved);
|
out.writeShort(_reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,13 +17,13 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number
|
* Number Stores a floating point value in a formula value stored in a 8 byte
|
||||||
* Stores a floating point value in a formula
|
* field using IEEE notation
|
||||||
* value stored in a 8 byte field using IEEE notation
|
*
|
||||||
* @author Avik Sengupta
|
* @author Avik Sengupta
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @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;
|
public final static byte sid = 0x1f;
|
||||||
private final double field_1_value;
|
private final double field_1_value;
|
||||||
|
|
||||||
/** Create a NumberPtg from a byte array read from disk */
|
public NumberPtg(LittleEndianInput in) {
|
||||||
public NumberPtg(RecordInputStream in) {
|
|
||||||
this(in.readDouble());
|
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
|
* Create a NumberPtg from a string representation of the number Number
|
||||||
* that calls this method.
|
* format is not checked, it is expected to be validated in the parser that
|
||||||
* @param value : String representation of a floating point number
|
* calls this method.
|
||||||
|
*
|
||||||
|
* @param value String representation of a floating point number
|
||||||
*/
|
*/
|
||||||
public NumberPtg(String value) {
|
public NumberPtg(String value) {
|
||||||
this(Double.parseDouble(value));
|
this(Double.parseDouble(value));
|
||||||
@ -54,9 +55,9 @@ public final class NumberPtg extends ScalarConstantPtg {
|
|||||||
return field_1_value;
|
return field_1_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[ offset + 0 ] = sid;
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putDouble(array, offset + 1, getValue());
|
out.writeDouble(getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
@ -65,7 +66,6 @@ public final class NumberPtg extends ScalarConstantPtg {
|
|||||||
|
|
||||||
public String toFormulaString() {
|
public String toFormulaString() {
|
||||||
// TODO - java's rendering of double values is not quite same as excel's
|
// TODO - java's rendering of double values is not quite same as excel's
|
||||||
// Maybe use HSSFDataFormatter?
|
|
||||||
return String.valueOf(field_1_value);
|
return String.valueOf(field_1_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,18 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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
|
* While formula tokens are stored in RPN order and thus do not need parenthesis
|
||||||
* precedence reasons, Parenthesis tokens ARE written to ensure that user entered
|
* for precedence reasons, Parenthesis tokens ARE written to ensure that user
|
||||||
* parenthesis are displayed as-is on reading back
|
* 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)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public final class ParenthesisPtg extends ControlPtg {
|
public final class ParenthesisPtg extends ControlPtg {
|
||||||
@ -34,27 +35,24 @@ public final class ParenthesisPtg extends ControlPtg {
|
|||||||
public final static byte sid = 0x15;
|
public final static byte sid = 0x15;
|
||||||
|
|
||||||
public static final ControlPtg instance = new ParenthesisPtg();
|
public static final ControlPtg instance = new ParenthesisPtg();
|
||||||
|
|
||||||
private ParenthesisPtg() {
|
private ParenthesisPtg() {
|
||||||
// enforce singleton
|
// enforce singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset)
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[ offset + 0 ] = sid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize() {
|
||||||
{
|
|
||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString()
|
public String toFormulaString() {
|
||||||
{
|
|
||||||
return "()";
|
return "()";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String toFormulaString(String[] operands) {
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
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.
|
* 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.
|
* 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);
|
List temp = new ArrayList(4 + size / 2);
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
List arrayPtgs = null;
|
List arrayPtgs = null;
|
||||||
while (pos < size) {
|
while (pos < size) {
|
||||||
Ptg ptg = Ptg.createPtg( in );
|
Ptg ptg = Ptg.createPtg(in);
|
||||||
if (ptg instanceof ArrayPtg) {
|
if (ptg instanceof ArrayPtg) {
|
||||||
if (arrayPtgs == null) {
|
if (arrayPtgs == null) {
|
||||||
arrayPtgs = new ArrayList(5);
|
arrayPtgs = new ArrayList(5);
|
||||||
@ -77,7 +77,7 @@ public abstract class Ptg implements Cloneable {
|
|||||||
return toPtgArray(temp);
|
return toPtgArray(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Ptg createPtg(RecordInputStream in) {
|
public static Ptg createPtg(LittleEndianInput in) {
|
||||||
byte id = in.readByte();
|
byte id = in.readByte();
|
||||||
|
|
||||||
if (id < 0x20) {
|
if (id < 0x20) {
|
||||||
@ -97,7 +97,7 @@ public abstract class Ptg implements Cloneable {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Ptg createClassifiedPtg(byte id, RecordInputStream in) {
|
private static Ptg createClassifiedPtg(byte id, LittleEndianInput in) {
|
||||||
|
|
||||||
int baseId = id & 0x1F | 0x20;
|
int baseId = id & 0x1F | 0x20;
|
||||||
|
|
||||||
@ -126,9 +126,9 @@ public abstract class Ptg implements Cloneable {
|
|||||||
Integer.toHexString(id) + " (" + ( int ) id + ")");
|
Integer.toHexString(id) + " (" + ( int ) id + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Ptg createBasePtg(byte id, RecordInputStream in) {
|
private static Ptg createBasePtg(byte id, LittleEndianInput in) {
|
||||||
switch(id) {
|
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 ExpPtg.sid: return new ExpPtg(in); // 0x01
|
||||||
case TblPtg.sid: return new TblPtg(in); // 0x02
|
case TblPtg.sid: return new TblPtg(in); // 0x02
|
||||||
case AddPtg.sid: return AddPtg.instance; // 0x03
|
case AddPtg.sid: return AddPtg.instance; // 0x03
|
||||||
@ -228,32 +228,30 @@ public abstract class Ptg implements Cloneable {
|
|||||||
* @return number of bytes written
|
* @return number of bytes written
|
||||||
*/
|
*/
|
||||||
public static int serializePtgs(Ptg[] ptgs, byte[] array, int offset) {
|
public static int serializePtgs(Ptg[] ptgs, byte[] array, int offset) {
|
||||||
int pos = 0;
|
int nTokens = ptgs.length;
|
||||||
int size = ptgs.length;
|
|
||||||
|
LittleEndianByteArrayOutputStream out = new LittleEndianByteArrayOutputStream(array, offset);
|
||||||
|
|
||||||
List arrayPtgs = null;
|
List arrayPtgs = null;
|
||||||
|
|
||||||
for (int k = 0; k < size; k++) {
|
for (int k = 0; k < nTokens; k++) {
|
||||||
Ptg ptg = ptgs[k];
|
Ptg ptg = ptgs[k];
|
||||||
|
|
||||||
ptg.writeBytes(array, pos + offset);
|
ptg.write(out);
|
||||||
if (ptg instanceof ArrayPtg) {
|
if (ptg instanceof ArrayPtg) {
|
||||||
if (arrayPtgs == null) {
|
if (arrayPtgs == null) {
|
||||||
arrayPtgs = new ArrayList(5);
|
arrayPtgs = new ArrayList(5);
|
||||||
}
|
}
|
||||||
arrayPtgs.add(ptg);
|
arrayPtgs.add(ptg);
|
||||||
pos += ArrayPtg.PLAIN_TOKEN_SIZE;
|
|
||||||
} else {
|
|
||||||
pos += ptg.getSize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (arrayPtgs != null) {
|
if (arrayPtgs != null) {
|
||||||
for (int i=0;i<arrayPtgs.size();i++) {
|
for (int i=0;i<arrayPtgs.size();i++) {
|
||||||
ArrayPtg p = (ArrayPtg)arrayPtgs.get(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 abstract int getDataSize();
|
||||||
|
|
||||||
public final byte[] getBytes()
|
public abstract void write(LittleEndianOutput out);
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return a string representation of this token alone
|
* return a string representation of this token alone
|
||||||
*/
|
*/
|
||||||
public abstract String toFormulaString();
|
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.
|
/** Overridden toString method to ensure object hash is not printed.
|
||||||
* This helps get rid of gratuitous diffs when comparing two dumps
|
* This helps get rid of gratuitous diffs when comparing two dumps
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Daniel Noll (daniel at nuix dot com dot au)
|
* @author Daniel Noll (daniel at nuix dot com dot au)
|
||||||
@ -40,9 +42,8 @@ public final class RangePtg extends OperationPtg {
|
|||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes( byte[] array, int offset )
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[ offset + 0 ] = sid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString()
|
public String toFormulaString()
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
@ -41,21 +41,25 @@ abstract class Ref2DPtgBase extends RefPtgBase {
|
|||||||
setColRelative(isColumnRelative);
|
setColRelative(isColumnRelative);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Ref2DPtgBase(RecordInputStream in) {
|
protected Ref2DPtgBase(LittleEndianInput in) {
|
||||||
readCoordinates(in);
|
readCoordinates(in);
|
||||||
}
|
}
|
||||||
public final void writeBytes(byte [] array, int offset) {
|
|
||||||
LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
|
public void write(LittleEndianOutput out) {
|
||||||
writeCoordinates(array, offset+1);
|
out.writeByte(getSid() + getPtgClass());
|
||||||
|
writeCoordinates(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String toFormulaString() {
|
public final String toFormulaString() {
|
||||||
return formatReferenceAsString();
|
return formatReferenceAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract byte getSid();
|
protected abstract byte getSid();
|
||||||
|
|
||||||
public final int getSize() {
|
public final int getSize() {
|
||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String toString() {
|
public final String toString() {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append(getClass().getName());
|
sb.append(getClass().getName());
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.util.CellReference;
|
||||||
import org.apache.poi.ss.formula.ExternSheetReferenceToken;
|
import org.apache.poi.ss.formula.ExternSheetReferenceToken;
|
||||||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
|
||||||
import org.apache.poi.ss.formula.WorkbookDependentFormula;
|
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>
|
* Title: Reference 3D Ptg <P>
|
||||||
@ -41,7 +41,7 @@ public final class Ref3DPtg extends RefPtgBase implements WorkbookDependentFormu
|
|||||||
/** Creates new AreaPtg */
|
/** Creates new AreaPtg */
|
||||||
public Ref3DPtg() {}
|
public Ref3DPtg() {}
|
||||||
|
|
||||||
public Ref3DPtg(RecordInputStream in) {
|
public Ref3DPtg(LittleEndianInput in) {
|
||||||
field_1_index_extern_sheet = in.readShort();
|
field_1_index_extern_sheet = in.readShort();
|
||||||
readCoordinates(in);
|
readCoordinates(in);
|
||||||
}
|
}
|
||||||
@ -66,10 +66,10 @@ public final class Ref3DPtg extends RefPtgBase implements WorkbookDependentFormu
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, 0 + offset, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(array, 1 + offset, getExternSheetIndex());
|
out.writeShort(getExternSheetIndex());
|
||||||
writeCoordinates(array, offset + 3);
|
writeCoordinates(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,10 +17,9 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.HSSFErrorConstants;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RefError - handles deleted cell reference
|
* RefError - handles deleted cell reference
|
||||||
@ -35,7 +34,7 @@ public final class RefErrorPtg extends OperandPtg {
|
|||||||
public RefErrorPtg() {
|
public RefErrorPtg() {
|
||||||
field_1_reserved = 0;
|
field_1_reserved = 0;
|
||||||
}
|
}
|
||||||
public RefErrorPtg(RecordInputStream in) {
|
public RefErrorPtg(LittleEndianInput in) {
|
||||||
field_1_reserved = in.readInt();
|
field_1_reserved = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +42,9 @@ public final class RefErrorPtg extends OperandPtg {
|
|||||||
return getClass().getName();
|
return getClass().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset+0, sid + getPtgClass());
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putInt(array,offset+1,field_1_reserved);
|
out.writeInt(field_1_reserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize()
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RefNPtg
|
* RefNPtg
|
||||||
@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
|
|||||||
public final class RefNPtg extends Ref2DPtgBase {
|
public final class RefNPtg extends Ref2DPtgBase {
|
||||||
public final static byte sid = 0x2C;
|
public final static byte sid = 0x2C;
|
||||||
|
|
||||||
public RefNPtg(RecordInputStream in) {
|
public RefNPtg(LittleEndianInput in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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)
|
* ReferencePtg - handles references (such as A1, A2, IA4)
|
||||||
@ -39,7 +39,7 @@ public final class RefPtg extends Ref2DPtgBase {
|
|||||||
super(row, column, isRowRelative, isColumnRelative);
|
super(row, column, isRowRelative, isColumnRelative);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RefPtg(RecordInputStream in) {
|
public RefPtg(LittleEndianInput in) {
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,14 +17,15 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.hssf.util.CellReference;
|
||||||
import org.apache.poi.util.BitField;
|
import org.apache.poi.util.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
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)
|
* ReferencePtgBase - handles references (such as A1, A2, IA4)
|
||||||
|
*
|
||||||
* @author Andrew C. Oliver (acoliver@apache.org)
|
* @author Andrew C. Oliver (acoliver@apache.org)
|
||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @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 */
|
/** The row index - zero based unsigned 16 bit value */
|
||||||
private int field_1_row;
|
private int field_1_row;
|
||||||
/** Field 2
|
/**
|
||||||
* - lower 8 bits is the zero based unsigned byte column index
|
* Field 2 - lower 8 bits is the zero based unsigned byte column index - bit
|
||||||
* - bit 16 - isRowRelative
|
* 16 - isRowRelative - bit 15 - isColumnRelative
|
||||||
* - bit 15 - isColumnRelative
|
|
||||||
*/
|
*/
|
||||||
private int field_2_col;
|
private int field_2_col;
|
||||||
private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
|
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);
|
private static final BitField column = BitFieldFactory.getInstance(0x00FF);
|
||||||
|
|
||||||
protected RefPtgBase() {
|
protected RefPtgBase() {
|
||||||
//Required for clone methods
|
// Required for clone methods
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +53,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
|||||||
* numeric fields.
|
* numeric fields.
|
||||||
*/
|
*/
|
||||||
protected RefPtgBase(String cellref) {
|
protected RefPtgBase(String cellref) {
|
||||||
CellReference c= new CellReference(cellref);
|
CellReference c = new CellReference(cellref);
|
||||||
setRow(c.getRow());
|
setRow(c.getRow());
|
||||||
setColumn(c.getCol());
|
setColumn(c.getCol());
|
||||||
setColRelative(!c.isColAbsolute());
|
setColRelative(!c.isColAbsolute());
|
||||||
@ -67,26 +67,27 @@ public abstract class RefPtgBase extends OperandPtg {
|
|||||||
setColRelative(isColumnRelative);
|
setColRelative(isColumnRelative);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void readCoordinates(RecordInputStream in) {
|
protected final void readCoordinates(LittleEndianInput in) {
|
||||||
field_1_row = in.readUShort();
|
field_1_row = in.readUShort();
|
||||||
field_2_col = in.readUShort();
|
field_2_col = in.readUShort();
|
||||||
}
|
}
|
||||||
protected final void writeCoordinates(byte[] array, int offset) {
|
|
||||||
LittleEndian.putUShort(array, offset + 0, field_1_row);
|
protected final void writeCoordinates(LittleEndianOutput out) {
|
||||||
LittleEndian.putUShort(array, offset + 2, field_2_col);
|
out.writeShort(field_1_row);
|
||||||
|
out.writeShort(field_2_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setRow(int row) {
|
public final void setRow(int rowIndex) {
|
||||||
if(row < 0 || row >= MAX_ROW_NUMBER) {
|
if (rowIndex < 0 || rowIndex >= MAX_ROW_NUMBER) {
|
||||||
throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + 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
|
* @return the row number as an int, between 0 and 65535
|
||||||
*/
|
*/
|
||||||
public final int getRow(){
|
public final int getRow() {
|
||||||
return field_1_row;
|
return field_1_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void setRowRelative(boolean rel) {
|
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() {
|
public final boolean isColRelative() {
|
||||||
@ -103,11 +104,11 @@ public abstract class RefPtgBase extends OperandPtg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final void setColRelative(boolean rel) {
|
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) {
|
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");
|
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
|
||||||
}
|
}
|
||||||
field_2_col = column.setValue(field_2_col, col);
|
field_2_col = column.setValue(field_2_col, col);
|
||||||
@ -116,6 +117,7 @@ public abstract class RefPtgBase extends OperandPtg {
|
|||||||
public final int getColumn() {
|
public final int getColumn() {
|
||||||
return column.getValue(field_2_col);
|
return column.getValue(field_2_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final String formatReferenceAsString() {
|
protected final String formatReferenceAsString() {
|
||||||
// Only make cell references as needed. Memory is an issue
|
// Only make cell references as needed. Memory is an issue
|
||||||
CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative());
|
CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative());
|
||||||
|
@ -17,9 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.BitField;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,28 +30,25 @@ import org.apache.poi.util.StringUtil;
|
|||||||
* @author Bernard Chesnoy
|
* @author Bernard Chesnoy
|
||||||
*/
|
*/
|
||||||
public final class StringPtg extends ScalarConstantPtg {
|
public final class StringPtg extends ScalarConstantPtg {
|
||||||
public final static int SIZE = 9;
|
|
||||||
public final static byte sid = 0x17;
|
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 static final char FORMULA_DELIMITER = '"';
|
||||||
|
|
||||||
|
private final boolean _is16bitUnicode;
|
||||||
/**
|
/**
|
||||||
* NOTE: OO doc says 16bit length, but BiffViewer says 8 Book says something
|
* NOTE: OO doc says 16bit length, but BiffViewer says 8 Book says something
|
||||||
* totally different, so don't look there!
|
* 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;
|
private final String field_3_string;
|
||||||
|
|
||||||
/** Create a StringPtg from a stream */
|
/** Create a StringPtg from a stream */
|
||||||
public StringPtg(RecordInputStream in) {
|
public StringPtg(LittleEndianInput in) {
|
||||||
field_1_length = in.readUByte();
|
int nChars = in.readUByte(); // Note - nChars is 8-bit
|
||||||
field_2_options = in.readByte();
|
_is16bitUnicode = (in.readByte() & 0x01) != 0;
|
||||||
if (fHighByte.isSet(field_2_options)) {
|
if (_is16bitUnicode) {
|
||||||
field_3_string = in.readUnicodeLEString(field_1_length);
|
field_3_string = StringUtil.readUnicodeLE(in, nChars);
|
||||||
} else {
|
} 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(
|
throw new IllegalArgumentException(
|
||||||
"String literals in formulas can't be bigger than 255 characters ASCII");
|
"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_3_string = value;
|
||||||
field_1_length = value.length(); // for the moment, we support only ASCII strings in formulas we create
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return field_3_string;
|
return field_3_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte[] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[offset + 0] = sid;
|
out.writeByte(sid + getPtgClass());
|
||||||
array[offset + 1] = (byte) field_1_length;
|
out.writeByte(field_3_string.length()); // Note - nChars is 8-bit
|
||||||
array[offset + 2] = field_2_options;
|
out.writeByte(_is16bitUnicode ? 0x01 : 0x00);
|
||||||
if (fHighByte.isSet(field_2_options)) {
|
if (_is16bitUnicode) {
|
||||||
StringUtil.putUnicodeLE(getValue(), array, offset + 3);
|
StringUtil.putUnicodeLE(field_3_string, out);
|
||||||
} else {
|
} else {
|
||||||
StringUtil.putCompressedUnicode(getValue(), array, offset + 3);
|
StringUtil.putCompressedUnicode(field_3_string, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
if (fHighByte.isSet(field_2_options)) {
|
return 3 + field_3_string.length() * (_is16bitUnicode ? 2 : 1);
|
||||||
return 2 * field_1_length + 3;
|
|
||||||
} else {
|
|
||||||
return field_1_length + 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString() {
|
public String toFormulaString() {
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordFormatException;
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This ptg indicates a data table.
|
* This ptg indicates a data table.
|
||||||
@ -43,15 +43,15 @@ public final class TblPtg extends ControlPtg {
|
|||||||
/** The column number of the upper left corner */
|
/** The column number of the upper left corner */
|
||||||
private final int field_2_first_col;
|
private final int field_2_first_col;
|
||||||
|
|
||||||
public TblPtg(RecordInputStream in) {
|
public TblPtg(LittleEndianInput in) {
|
||||||
field_1_first_row = in.readUShort();
|
field_1_first_row = in.readUShort();
|
||||||
field_2_first_col = in.readUShort();
|
field_2_first_col = in.readUShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes(byte [] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
LittleEndian.putByte(array, offset+0, sid);
|
out.writeByte(sid + getPtgClass());
|
||||||
LittleEndian.putUShort(array, offset+1, field_1_first_row);
|
out.writeShort(field_1_first_row);
|
||||||
LittleEndian.putUShort(array, offset+3, field_2_first_col);
|
out.writeShort(field_2_first_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
package org.apache.poi.hssf.record.formula;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
@ -39,9 +41,8 @@ public final class UnionPtg extends OperationPtg {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBytes( byte[] array, int offset )
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(sid + getPtgClass());
|
||||||
array[ offset + 0 ] = sid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString()
|
public String toFormulaString()
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.hssf.record.formula;
|
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 {
|
public class UnknownPtg extends Ptg {
|
||||||
private short size = 1;
|
private short size = 1;
|
||||||
|
private final int _sid;
|
||||||
|
|
||||||
/** Creates new UnknownPtg */
|
public UnknownPtg(int sid) {
|
||||||
|
_sid = sid;
|
||||||
public UnknownPtg()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnknownPtg(RecordInputStream in) {
|
|
||||||
// doesn't need anything
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBaseToken() {
|
public boolean isBaseToken() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public void writeBytes(byte [] array, int offset)
|
public void write(LittleEndianOutput out) {
|
||||||
{
|
out.writeByte(_sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize()
|
public int getSize()
|
||||||
@ -55,8 +50,6 @@ public class UnknownPtg extends Ptg {
|
|||||||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
|
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
|
||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
return new UnknownPtg();
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
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.
|
* Common superclass of all value operators. Subclasses include all unary and
|
||||||
* Subclasses include all unary and binary operators except for the reference operators (IntersectionPtg, RangePtg, UnionPtg)
|
* binary operators except for the reference operators (IntersectionPtg,
|
||||||
|
* RangePtg, UnionPtg)
|
||||||
*
|
*
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
@ -38,8 +39,8 @@ public abstract class ValueOperatorPtg extends OperationPtg {
|
|||||||
return Ptg.CLASS_VALUE;
|
return Ptg.CLASS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void writeBytes(byte[] array, int offset) {
|
public void write(LittleEndianOutput out) {
|
||||||
array[offset + 0] = getSid();
|
out.writeByte(getSid());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract byte getSid();
|
protected abstract byte getSid();
|
||||||
@ -47,6 +48,7 @@ public abstract class ValueOperatorPtg extends OperationPtg {
|
|||||||
public final int getSize() {
|
public final int getSize() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String toFormulaString() {
|
public final String toFormulaString() {
|
||||||
// TODO - prune this method out of the hierarchy
|
// TODO - prune this method out of the hierarchy
|
||||||
throw new RuntimeException("toFormulaString(String[] operands) should be used for subclasses of OperationPtgs");
|
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) {
|
if(sr == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
|
if(sr.isBuiltin()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return sr.getName();
|
return sr.getName();
|
||||||
@ -990,7 +990,7 @@ public class HSSFCellStyle implements CellStyle
|
|||||||
if(sr == null) {
|
if(sr == null) {
|
||||||
sr = workbook.createStyleRecord(index);
|
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!");
|
throw new IllegalArgumentException("Unable to set user specified style names for built in styles!");
|
||||||
}
|
}
|
||||||
sr.setName(styleName);
|
sr.setName(styleName);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,436 +15,313 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.filesystem;
|
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
|
* This class provides methods to read a DocumentEntry managed by a
|
||||||
* Filesystem instance.
|
* {@link POIFSFileSystem} instance.
|
||||||
*
|
*
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
* @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
|
private static final int SIZE_SHORT = 2;
|
||||||
extends InputStream
|
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;
|
private int _current_offset;
|
||||||
|
|
||||||
// current marked offset into the Document (used by mark and
|
/** current marked offset into the Document (used by mark and reset) */
|
||||||
// reset)
|
|
||||||
private int _marked_offset;
|
private int _marked_offset;
|
||||||
|
|
||||||
// the Document's size
|
/** the Document's size */
|
||||||
private int _document_size;
|
private int _document_size;
|
||||||
|
|
||||||
// have we been closed?
|
/** have we been closed? */
|
||||||
private boolean _closed;
|
private boolean _closed;
|
||||||
|
|
||||||
// the actual Document
|
/** the actual Document */
|
||||||
private POIFSDocument _document;
|
private POIFSDocument _document;
|
||||||
|
|
||||||
// buffer used to read one byte at a time
|
/** the data block containing the current stream pointer */
|
||||||
private byte[] _tiny_buffer;
|
private DataInputBlock _currentBlock;
|
||||||
|
|
||||||
// returned by read operations if we're at end of document
|
|
||||||
static private final int EOD = -1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an InputStream from the specified DocumentEntry
|
* Create an InputStream from the specified DocumentEntry
|
||||||
*
|
*
|
||||||
* @param document the DocumentEntry to be read
|
* @param document the DocumentEntry to be read
|
||||||
*
|
*
|
||||||
* @exception IOException if the DocumentEntry cannot be opened
|
* @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
|
||||||
* (like, maybe it has been deleted?)
|
* been deleted?)
|
||||||
*/
|
*/
|
||||||
|
public DocumentInputStream(DocumentEntry document) throws IOException {
|
||||||
public DocumentInputStream(final DocumentEntry document)
|
if (!(document instanceof DocumentNode)) {
|
||||||
throws IOException
|
throw new IOException("Cannot open internal document storage");
|
||||||
{
|
}
|
||||||
_current_offset = 0;
|
_current_offset = 0;
|
||||||
_marked_offset = 0;
|
_marked_offset = 0;
|
||||||
_document_size = document.getSize();
|
_document_size = document.getSize();
|
||||||
_closed = false;
|
_closed = false;
|
||||||
_tiny_buffer = null;
|
_document = ((DocumentNode) document).getDocument();
|
||||||
if (document instanceof DocumentNode)
|
_currentBlock = getDataInputBlock(0);
|
||||||
{
|
|
||||||
_document = (( DocumentNode ) document).getDocument();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new IOException("Cannot open internal document storage");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an InputStream from the specified Document
|
* Create an InputStream from the specified Document
|
||||||
*
|
*
|
||||||
* @param document the Document to be read
|
* @param document the Document to be read
|
||||||
*
|
|
||||||
* @exception IOException if the DocumentEntry cannot be opened
|
|
||||||
* (like, maybe it has been deleted?)
|
|
||||||
*/
|
*/
|
||||||
|
public DocumentInputStream(POIFSDocument document) {
|
||||||
public DocumentInputStream(final POIFSDocument document)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_current_offset = 0;
|
_current_offset = 0;
|
||||||
_marked_offset = 0;
|
_marked_offset = 0;
|
||||||
_document_size = document.getSize();
|
_document_size = document.getSize();
|
||||||
_closed = false;
|
_closed = false;
|
||||||
_tiny_buffer = null;
|
|
||||||
_document = document;
|
_document = document;
|
||||||
|
_currentBlock = getDataInputBlock(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public int available() {
|
||||||
* Returns the number of bytes that can be read (or skipped over)
|
if (_closed) {
|
||||||
* from this input stream without blocking by the next caller of a
|
throw new IllegalStateException("cannot perform requested operation on a closed stream");
|
||||||
* method for this input stream. The next caller might be the same
|
}
|
||||||
* thread or or another thread.
|
|
||||||
*
|
|
||||||
* @return the number of bytes that can be read from this input
|
|
||||||
* stream without blocking.
|
|
||||||
*
|
|
||||||
* @exception IOException on error (such as the stream has been
|
|
||||||
* closed)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int available()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
dieIfClosed();
|
|
||||||
return _document_size - _current_offset;
|
return _document_size - _current_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void close() {
|
||||||
* Closes this input stream and releases any system resources
|
|
||||||
* associated with the stream.
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_closed = true;
|
_closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void mark(int ignoredReadlimit) {
|
||||||
* Marks the current position in this input stream. A subsequent
|
|
||||||
* call to the reset method repositions this stream at the last
|
|
||||||
* marked position so that subsequent reads re-read the same
|
|
||||||
* bytes.
|
|
||||||
* <p>
|
|
||||||
* The readlimit arguments tells this input stream to allow that
|
|
||||||
* many bytes to be read before the mark position gets
|
|
||||||
* invalidated. This implementation, however, does not care.
|
|
||||||
* <p>
|
|
||||||
* The general contract of mark is that, if the method
|
|
||||||
* markSupported returns true, the stream somehow remembers all
|
|
||||||
* the bytes read after the call to mark and stands ready to
|
|
||||||
* supply those same bytes again if and whenever the method reset
|
|
||||||
* is called. However, the stream is not required to remember any
|
|
||||||
* data at all if more than readlimit bytes are read from the
|
|
||||||
* stream before reset is called. But this stream will.
|
|
||||||
*
|
|
||||||
* @param ignoredReadlimit the maximum limit of bytes that can be
|
|
||||||
* read before the mark position becomes
|
|
||||||
* invalid. Ignored by this
|
|
||||||
* implementation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void mark(int ignoredReadlimit)
|
|
||||||
{
|
|
||||||
_marked_offset = _current_offset;
|
_marked_offset = _current_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if this input stream supports the mark and reset methods.
|
* 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private DataInputBlock getDataInputBlock(int offset) {
|
||||||
* Reads the next byte of data from the input stream. The value
|
return _document.getDataInputBlock(offset);
|
||||||
* byte is returned as an int in the range 0 to 255. If no byte is
|
}
|
||||||
* available because the end of the stream has been reached, the
|
|
||||||
* value -1 is returned. The definition of this method in
|
|
||||||
* java.io.InputStream allows this method to block, but it won't.
|
|
||||||
*
|
|
||||||
* @return the next byte of data, or -1 if the end of the stream
|
|
||||||
* is reached.
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int read()
|
public int read() throws IOException {
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
dieIfClosed();
|
dieIfClosed();
|
||||||
if (atEOD())
|
if (atEOD()) {
|
||||||
{
|
return EOF;
|
||||||
return EOD;
|
|
||||||
}
|
}
|
||||||
if (_tiny_buffer == null)
|
int result = _currentBlock.readUByte();
|
||||||
{
|
_current_offset++;
|
||||||
_tiny_buffer = new byte[ 1 ];
|
if (_currentBlock.available() < 1) {
|
||||||
|
_currentBlock = getDataInputBlock(_current_offset);
|
||||||
}
|
}
|
||||||
_document.read(_tiny_buffer, _current_offset++);
|
return result;
|
||||||
return ((int)_tiny_buffer[ 0 ]) & 0x000000FF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public int read(byte[] b) throws IOException {
|
||||||
* Reads some number of bytes from the input stream and stores
|
|
||||||
* them into the buffer array b. The number of bytes actually read
|
|
||||||
* is returned as an integer. The definition of this method in
|
|
||||||
* java.io.InputStream allows this method to block, but it won't.
|
|
||||||
* <p>
|
|
||||||
* If b is null, a NullPointerException is thrown. If the length
|
|
||||||
* of b is zero, then no bytes are read and 0 is returned;
|
|
||||||
* otherwise, there is an attempt to read at least one byte. If no
|
|
||||||
* byte is available because the stream is at end of file, the
|
|
||||||
* value -1 is returned; otherwise, at least one byte is read and
|
|
||||||
* stored into b.
|
|
||||||
* <p>
|
|
||||||
* The first byte read is stored into element b[0], the next one
|
|
||||||
* into b[1], and so on. The number of bytes read is, at most,
|
|
||||||
* equal to the length of b. Let k be the number of bytes actually
|
|
||||||
* read; these bytes will be stored in elements b[0] through
|
|
||||||
* b[k-1], leaving elements b[k] through b[b.length-1] unaffected.
|
|
||||||
* <p>
|
|
||||||
* If the first byte cannot be read for any reason other than end
|
|
||||||
* of file, then an IOException is thrown. In particular, an
|
|
||||||
* IOException is thrown if the input stream has been closed.
|
|
||||||
* <p>
|
|
||||||
* The read(b) method for class InputStream has the same effect as:
|
|
||||||
* <p>
|
|
||||||
* <code>read(b, 0, b.length)</code>
|
|
||||||
*
|
|
||||||
* @param b the buffer into which the data is read.
|
|
||||||
*
|
|
||||||
* @return the total number of bytes read into the buffer, or -1
|
|
||||||
* if there is no more data because the end of the stream
|
|
||||||
* has been reached.
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
* @exception NullPointerException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int read(final byte [] b)
|
|
||||||
throws IOException, NullPointerException
|
|
||||||
{
|
|
||||||
return read(b, 0, b.length);
|
return read(b, 0, b.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
* Reads up to len bytes of data from the input stream into an
|
|
||||||
* array of bytes. An attempt is made to read as many as len
|
|
||||||
* bytes, but a smaller number may be read, possibly zero. The
|
|
||||||
* number of bytes actually read is returned as an integer.
|
|
||||||
* <p>
|
|
||||||
* The definition of this method in java.io.InputStream allows it
|
|
||||||
* to block, but it won't.
|
|
||||||
* <p>
|
|
||||||
* If b is null, a NullPointerException is thrown.
|
|
||||||
* <p>
|
|
||||||
* If off is negative, or len is negative, or off+len is greater
|
|
||||||
* than the length of the array b, then an
|
|
||||||
* IndexOutOfBoundsException is thrown.
|
|
||||||
* <p>
|
|
||||||
* If len is zero, then no bytes are read and 0 is returned;
|
|
||||||
* otherwise, there is an attempt to read at least one byte. If no
|
|
||||||
* byte is available because the stream is at end of file, the
|
|
||||||
* value -1 is returned; otherwise, at least one byte is read and
|
|
||||||
* stored into b.
|
|
||||||
* <p>
|
|
||||||
* The first byte read is stored into element b[off], the next one
|
|
||||||
* into b[off+1], and so on. The number of bytes read is, at most,
|
|
||||||
* equal to len. Let k be the number of bytes actually read; these
|
|
||||||
* bytes will be stored in elements b[off] through b[off+k-1],
|
|
||||||
* leaving elements b[off+k] through b[off+len-1] unaffected.
|
|
||||||
* <p>
|
|
||||||
* In every case, elements b[0] through b[off] and elements
|
|
||||||
* b[off+len] through b[b.length-1] are unaffected.
|
|
||||||
* <p>
|
|
||||||
* If the first byte cannot be read for any reason other than end
|
|
||||||
* of file, then an IOException is thrown. In particular, an
|
|
||||||
* IOException is thrown if the input stream has been closed.
|
|
||||||
*
|
|
||||||
* @param b the buffer into which the data is read.
|
|
||||||
* @param off the start offset in array b at which the data is
|
|
||||||
* written.
|
|
||||||
* @param len the maximum number of bytes to read.
|
|
||||||
*
|
|
||||||
* @return the total number of bytes read into the buffer, or -1
|
|
||||||
* if there is no more data because the end of the stream
|
|
||||||
* has been reached.
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
* @exception NullPointerException
|
|
||||||
* @exception IndexOutOfBoundsException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int read(final byte [] b, final int off, final int len)
|
|
||||||
throws IOException, NullPointerException, IndexOutOfBoundsException
|
|
||||||
{
|
|
||||||
dieIfClosed();
|
dieIfClosed();
|
||||||
if (b == null)
|
if (b == null) {
|
||||||
{
|
throw new IllegalArgumentException("buffer must not be null");
|
||||||
throw new NullPointerException("buffer is null");
|
|
||||||
}
|
}
|
||||||
if ((off < 0) || (len < 0) || (b.length < (off + len)))
|
if (off < 0 || len < 0 || b.length < off + len) {
|
||||||
{
|
throw new IndexOutOfBoundsException("can't read past buffer boundaries");
|
||||||
throw new IndexOutOfBoundsException(
|
|
||||||
"can't read past buffer boundaries");
|
|
||||||
}
|
}
|
||||||
if (len == 0)
|
if (len == 0) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (atEOD())
|
if (atEOD()) {
|
||||||
{
|
return EOF;
|
||||||
return EOD;
|
|
||||||
}
|
}
|
||||||
int limit = Math.min(available(), len);
|
int limit = Math.min(available(), len);
|
||||||
|
readFully(b, off, limit);
|
||||||
if ((off == 0) && (limit == b.length))
|
|
||||||
{
|
|
||||||
_document.read(b, _current_offset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] buffer = new byte[ limit ];
|
|
||||||
|
|
||||||
_document.read(buffer, _current_offset);
|
|
||||||
System.arraycopy(buffer, 0, b, off, limit);
|
|
||||||
}
|
|
||||||
_current_offset += limit;
|
|
||||||
return limit;
|
return limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repositions this stream to the position at the time the mark
|
* Repositions this stream to the position at the time the mark() method was
|
||||||
* method was last called on this input stream.
|
* last called on this input stream. If mark() has not been called this
|
||||||
* <p>
|
* method repositions the stream to its beginning.
|
||||||
* The general contract of reset is:
|
|
||||||
* <p>
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* If the method markSupported returns true, then:
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* If the method mark has not been called since the
|
|
||||||
* stream was created, or the number of bytes read
|
|
||||||
* from the stream since mark was last called is
|
|
||||||
* larger than the argument to mark at that last
|
|
||||||
* call, then an IOException might be thrown.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* If such an IOException is not thrown, then the
|
|
||||||
* stream is reset to a state such that all the
|
|
||||||
* bytes read since the most recent call to mark
|
|
||||||
* (or since the start of the file, if mark has not
|
|
||||||
* been called) will be resupplied to subsequent
|
|
||||||
* callers of the read method, followed by any
|
|
||||||
* bytes that otherwise would have been the next
|
|
||||||
* input data as of the time of the call to reset.
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* If the method markSupported returns false, then:
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* The call to reset may throw an IOException.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* If an IOException is not thrown, then the
|
|
||||||
* stream is reset to a fixed state that depends
|
|
||||||
* on the particular type of the input and how it
|
|
||||||
* was created. The bytes that will be supplied to
|
|
||||||
* subsequent callers of the read method depend on
|
|
||||||
* the particular type of the input stream.
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
* All well and good ... this class's markSupported method returns
|
|
||||||
* true and this method does not care whether you've called mark
|
|
||||||
* at all, or whether you've exceeded the number of bytes
|
|
||||||
* specified in the last call to mark. We're basically walking a
|
|
||||||
* byte array ... mark and reset to your heart's content.
|
|
||||||
*/
|
*/
|
||||||
|
public void reset() {
|
||||||
public void reset()
|
|
||||||
{
|
|
||||||
_current_offset = _marked_offset;
|
_current_offset = _marked_offset;
|
||||||
|
_currentBlock = getDataInputBlock(_current_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public long skip(long n) throws IOException {
|
||||||
* Skips over and discards n bytes of data from this input
|
|
||||||
* stream. The skip method may, for a variety of reasons, end up
|
|
||||||
* skipping over some smaller number of bytes, possibly 0. This
|
|
||||||
* may result from any of a number of conditions; reaching end of
|
|
||||||
* file before n bytes have been skipped is only one
|
|
||||||
* possibility. The actual number of bytes skipped is returned. If
|
|
||||||
* n is negative, no bytes are skipped.
|
|
||||||
*
|
|
||||||
* @param n the number of bytes to be skipped.
|
|
||||||
*
|
|
||||||
* @return the actual number of bytes skipped.
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public long skip(final long n)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
dieIfClosed();
|
dieIfClosed();
|
||||||
if (n < 0)
|
if (n < 0) {
|
||||||
{
|
|
||||||
return 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
|
// wrap around in converting a VERY large long to an int
|
||||||
new_offset = _document_size;
|
new_offset = _document_size;
|
||||||
}
|
} else if (new_offset > _document_size) {
|
||||||
else if (new_offset > _document_size)
|
|
||||||
{
|
|
||||||
new_offset = _document_size;
|
new_offset = _document_size;
|
||||||
}
|
}
|
||||||
long rval = new_offset - _current_offset;
|
long rval = new_offset - _current_offset;
|
||||||
|
|
||||||
_current_offset = new_offset;
|
_current_offset = new_offset;
|
||||||
|
_currentBlock = getDataInputBlock(_current_offset);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dieIfClosed()
|
private void dieIfClosed() throws IOException {
|
||||||
throws IOException
|
if (_closed) {
|
||||||
{
|
throw new IOException("cannot perform requested operation on a closed stream");
|
||||||
if (_closed)
|
|
||||||
{
|
|
||||||
throw new IOException(
|
|
||||||
"cannot perform requested operation on a closed stream");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean atEOD()
|
private boolean atEOD() {
|
||||||
{
|
|
||||||
return _current_offset == _document_size;
|
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
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,20 +15,25 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.filesystem;
|
package org.apache.poi.poifs.filesystem;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
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.common.POIFSConstants;
|
||||||
import org.apache.poi.poifs.dev.POIFSViewable;
|
import org.apache.poi.poifs.dev.POIFSViewable;
|
||||||
import org.apache.poi.poifs.property.DocumentProperty;
|
import org.apache.poi.poifs.property.DocumentProperty;
|
||||||
import org.apache.poi.poifs.property.Property;
|
import org.apache.poi.poifs.property.Property;
|
||||||
import org.apache.poi.poifs.storage.BlockWritable;
|
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.DocumentBlock;
|
||||||
|
import org.apache.poi.poifs.storage.ListManagedBlock;
|
||||||
import org.apache.poi.poifs.storage.RawDataBlock;
|
import org.apache.poi.poifs.storage.RawDataBlock;
|
||||||
import org.apache.poi.poifs.storage.SmallDocumentBlock;
|
import org.apache.poi.poifs.storage.SmallDocumentBlock;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
@ -39,10 +43,9 @@ import org.apache.poi.util.HexDump;
|
|||||||
*
|
*
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
* @author Marc Johnson (mjohnson at apache dot org)
|
||||||
*/
|
*/
|
||||||
|
public final class POIFSDocument implements BATManaged, BlockWritable, POIFSViewable {
|
||||||
public class POIFSDocument
|
private static final DocumentBlock[] EMPTY_BIG_BLOCK_ARRAY = { };
|
||||||
implements BATManaged, BlockWritable, POIFSViewable
|
private static final SmallDocumentBlock[] EMPTY_SMALL_BLOCK_ARRAY = { };
|
||||||
{
|
|
||||||
private DocumentProperty _property;
|
private DocumentProperty _property;
|
||||||
private int _size;
|
private int _size;
|
||||||
|
|
||||||
@ -56,21 +59,32 @@ public class POIFSDocument
|
|||||||
* @param name the name of the POIFSDocument
|
* @param name the name of the POIFSDocument
|
||||||
* @param blocks the big blocks making up the POIFSDocument
|
* @param blocks the big blocks making up the POIFSDocument
|
||||||
* @param length the actual length of the POIFSDocument
|
* @param length the actual length of the POIFSDocument
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public POIFSDocument(String name, RawDataBlock[] blocks, int length) throws IOException {
|
||||||
public POIFSDocument(final String name, final RawDataBlock [] blocks,
|
|
||||||
final int length)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_size = length;
|
_size = length;
|
||||||
_big_store = new BigBlockStore(blocks);
|
_big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
|
||||||
_property = new DocumentProperty(name, _size);
|
_property = new DocumentProperty(name, _size);
|
||||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||||
_property.setDocument(this);
|
_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
|
* Constructor from small blocks
|
||||||
*
|
*
|
||||||
@ -78,20 +92,9 @@ public class POIFSDocument
|
|||||||
* @param blocks the small blocks making up the POIFSDocument
|
* @param blocks the small blocks making up the POIFSDocument
|
||||||
* @param length the actual length of the POIFSDocument
|
* @param length the actual length of the POIFSDocument
|
||||||
*/
|
*/
|
||||||
|
public POIFSDocument(String name, SmallDocumentBlock[] blocks, int length) {
|
||||||
public POIFSDocument(final String name,
|
|
||||||
final SmallDocumentBlock [] blocks, final int length)
|
|
||||||
{
|
|
||||||
_size = length;
|
_size = length;
|
||||||
try
|
_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
|
||||||
{
|
|
||||||
_big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
|
|
||||||
}
|
|
||||||
catch (IOException ignored)
|
|
||||||
{
|
|
||||||
|
|
||||||
// can't happen with that constructor
|
|
||||||
}
|
|
||||||
_property = new DocumentProperty(name, _size);
|
_property = new DocumentProperty(name, _size);
|
||||||
_small_store = new SmallBlockStore(blocks);
|
_small_store = new SmallBlockStore(blocks);
|
||||||
_property.setDocument(this);
|
_property.setDocument(this);
|
||||||
@ -103,26 +106,17 @@ public class POIFSDocument
|
|||||||
* @param name the name of the POIFSDocument
|
* @param name the name of the POIFSDocument
|
||||||
* @param blocks the small blocks making up the POIFSDocument
|
* @param blocks the small blocks making up the POIFSDocument
|
||||||
* @param length the actual length of the POIFSDocument
|
* @param length the actual length of the POIFSDocument
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public POIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
|
||||||
public POIFSDocument(final String name, final ListManagedBlock [] blocks,
|
|
||||||
final int length)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_size = length;
|
_size = length;
|
||||||
_property = new DocumentProperty(name, _size);
|
_property = new DocumentProperty(name, _size);
|
||||||
_property.setDocument(this);
|
_property.setDocument(this);
|
||||||
if (Property.isSmall(_size))
|
if (Property.isSmall(_size)) {
|
||||||
{
|
_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
|
||||||
_big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
|
_small_store = new SmallBlockStore(convertRawBlocksToSmallBlocks(blocks));
|
||||||
_small_store = new SmallBlockStore(blocks);
|
} else {
|
||||||
}
|
_big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
|
||||||
else
|
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||||
{
|
|
||||||
_big_store = new BigBlockStore(blocks);
|
|
||||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,47 +125,33 @@ public class POIFSDocument
|
|||||||
*
|
*
|
||||||
* @param name the name of the POIFSDocument
|
* @param name the name of the POIFSDocument
|
||||||
* @param stream the InputStream we read data from
|
* @param stream the InputStream we read data from
|
||||||
*
|
|
||||||
* @exception IOException thrown on read errors
|
|
||||||
*/
|
*/
|
||||||
|
public POIFSDocument(String name, InputStream stream) throws IOException {
|
||||||
public POIFSDocument(final String name, final InputStream stream)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
List blocks = new ArrayList();
|
List blocks = new ArrayList();
|
||||||
|
|
||||||
_size = 0;
|
_size = 0;
|
||||||
while (true)
|
while (true) {
|
||||||
{
|
|
||||||
DocumentBlock block = new DocumentBlock(stream);
|
DocumentBlock block = new DocumentBlock(stream);
|
||||||
int blockSize = block.size();
|
int blockSize = block.size();
|
||||||
|
|
||||||
if (blockSize > 0)
|
if (blockSize > 0) {
|
||||||
{
|
|
||||||
blocks.add(block);
|
blocks.add(block);
|
||||||
_size += blockSize;
|
_size += blockSize;
|
||||||
}
|
}
|
||||||
if (block.partiallyRead())
|
if (block.partiallyRead()) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentBlock[] bigBlocks =
|
DocumentBlock[] bigBlocks = (DocumentBlock[]) blocks.toArray(new DocumentBlock[blocks.size()]);
|
||||||
( DocumentBlock [] ) blocks.toArray(new DocumentBlock[ 0 ]);
|
|
||||||
|
|
||||||
_big_store = new BigBlockStore(bigBlocks);
|
_big_store = new BigBlockStore(bigBlocks);
|
||||||
_property = new DocumentProperty(name, _size);
|
_property = new DocumentProperty(name, _size);
|
||||||
_property.setDocument(this);
|
_property.setDocument(this);
|
||||||
if (_property.shouldUseSmallBlocks())
|
if (_property.shouldUseSmallBlocks()) {
|
||||||
{
|
_small_store = new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks, _size));
|
||||||
_small_store =
|
_big_store = new BigBlockStore(new DocumentBlock[0]);
|
||||||
new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks,
|
} else {
|
||||||
_size));
|
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||||
_big_store = new BigBlockStore(new DocumentBlock[ 0 ]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,49 +161,32 @@ public class POIFSDocument
|
|||||||
* @param name the name of the POIFSDocument
|
* @param name the name of the POIFSDocument
|
||||||
* @param size the length of the POIFSDocument
|
* @param size the length of the POIFSDocument
|
||||||
* @param path the path of the POIFSDocument
|
* @param path the path of the POIFSDocument
|
||||||
* @param writer the writer who will eventually write the document
|
* @param writer the writer who will eventually write the document contents
|
||||||
* contents
|
|
||||||
*
|
|
||||||
* @exception IOException thrown on read errors
|
|
||||||
*/
|
*/
|
||||||
|
public POIFSDocument(String name, int size, POIFSDocumentPath path, POIFSWriterListener writer) {
|
||||||
public POIFSDocument(final String name, final int size,
|
|
||||||
final POIFSDocumentPath path,
|
|
||||||
final POIFSWriterListener writer)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_size = size;
|
_size = size;
|
||||||
_property = new DocumentProperty(name, _size);
|
_property = new DocumentProperty(name, _size);
|
||||||
_property.setDocument(this);
|
_property.setDocument(this);
|
||||||
if (_property.shouldUseSmallBlocks())
|
if (_property.shouldUseSmallBlocks()) {
|
||||||
{
|
|
||||||
_small_store = new SmallBlockStore(path, name, size, writer);
|
_small_store = new SmallBlockStore(path, name, size, writer);
|
||||||
_big_store = new BigBlockStore(new Object[ 0 ]);
|
_big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
|
||||||
}
|
} else {
|
||||||
else
|
_small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
|
||||||
{
|
|
||||||
_small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
|
|
||||||
_big_store = new BigBlockStore(path, name, size, writer);
|
_big_store = new BigBlockStore(path, name, size, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the array of SmallDocumentBlocks used
|
|
||||||
*
|
|
||||||
* @return array of SmallDocumentBlocks; may be empty, cannot be null
|
* @return array of SmallDocumentBlocks; may be empty, cannot be null
|
||||||
*/
|
*/
|
||||||
|
public BlockWritable[] getSmallBlocks() {
|
||||||
public BlockWritable [] getSmallBlocks()
|
|
||||||
{
|
|
||||||
return _small_store.getBlocks();
|
return _small_store.getBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return size of the document
|
* @return size of the document
|
||||||
*/
|
*/
|
||||||
|
public int getSize() {
|
||||||
public int getSize()
|
|
||||||
{
|
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,28 +195,70 @@ public class POIFSDocument
|
|||||||
*
|
*
|
||||||
* @param buffer the buffer to write to
|
* @param buffer the buffer to write to
|
||||||
* @param offset the offset into our storage to read from
|
* @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)
|
DataInputBlock currentBlock = getDataInputBlock(offset);
|
||||||
{
|
|
||||||
if (_property.shouldUseSmallBlocks())
|
int blockAvailable = currentBlock.available();
|
||||||
{
|
if (blockAvailable > len) {
|
||||||
SmallDocumentBlock.read(_small_store.getBlocks(), buffer, offset);
|
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
|
* @return the instance's DocumentProperty
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DocumentProperty getDocumentProperty()
|
DocumentProperty getDocumentProperty() {
|
||||||
{
|
|
||||||
return _property;
|
return _property;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,16 +267,9 @@ public class POIFSDocument
|
|||||||
/**
|
/**
|
||||||
* Write the storage to an OutputStream
|
* Write the storage to an OutputStream
|
||||||
*
|
*
|
||||||
* @param stream the OutputStream to which the stored data should
|
* @param stream the OutputStream to which the stored data should be written
|
||||||
* be written
|
|
||||||
*
|
|
||||||
* @exception IOException on problems writing to the specified
|
|
||||||
* stream
|
|
||||||
*/
|
*/
|
||||||
|
public void writeBlocks(OutputStream stream) throws IOException {
|
||||||
public void writeBlocks(final OutputStream stream)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_big_store.writeBlocks(stream);
|
_big_store.writeBlocks(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,21 +281,16 @@ public class POIFSDocument
|
|||||||
*
|
*
|
||||||
* @return count of BigBlock instances
|
* @return count of BigBlock instances
|
||||||
*/
|
*/
|
||||||
|
public int countBlocks() {
|
||||||
public int countBlocks()
|
|
||||||
{
|
|
||||||
return _big_store.countBlocks();
|
return _big_store.countBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the start block for this instance
|
* Set the start block for this instance
|
||||||
*
|
*
|
||||||
* @param index index into the array of blocks making up the
|
* @param index index into the array of blocks making up the filesystem
|
||||||
* filesystem
|
|
||||||
*/
|
*/
|
||||||
|
public void setStartBlock(int index) {
|
||||||
public void setStartBlock(final int index)
|
|
||||||
{
|
|
||||||
_property.setStartBlock(index);
|
_property.setStartBlock(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,41 +298,31 @@ public class POIFSDocument
|
|||||||
/* ********** START begin implementation of POIFSViewable ********** */
|
/* ********** START begin implementation of POIFSViewable ********** */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an array of objects, some of which may implement
|
* Get an array of objects, some of which may implement POIFSViewable
|
||||||
* POIFSViewable
|
|
||||||
*
|
*
|
||||||
* @return an array of Object; may not be null, but may be empty
|
* @return an array of Object; may not be null, but may be empty
|
||||||
*/
|
*/
|
||||||
|
public Object[] getViewableArray() {
|
||||||
public Object [] getViewableArray()
|
Object[] results = new Object[1];
|
||||||
{
|
|
||||||
Object[] results = new Object[ 1 ];
|
|
||||||
String result;
|
String result;
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
BlockWritable[] blocks = null;
|
BlockWritable[] blocks = null;
|
||||||
|
|
||||||
if (_big_store.isValid())
|
if (_big_store.isValid()) {
|
||||||
{
|
|
||||||
blocks = _big_store.getBlocks();
|
blocks = _big_store.getBlocks();
|
||||||
}
|
} else if (_small_store.isValid()) {
|
||||||
else if (_small_store.isValid())
|
|
||||||
{
|
|
||||||
blocks = _small_store.getBlocks();
|
blocks = _small_store.getBlocks();
|
||||||
}
|
}
|
||||||
if (blocks != null)
|
if (blocks != null) {
|
||||||
{
|
for (int k = 0; k < blocks.length; k++) {
|
||||||
for (int k = 0; k < blocks.length; k++)
|
blocks[k].writeBlocks(output);
|
||||||
{
|
|
||||||
blocks[ k ].writeBlocks(output);
|
|
||||||
}
|
}
|
||||||
byte[] data = output.toByteArray();
|
byte[] data = output.toByteArray();
|
||||||
|
|
||||||
if (data.length > _property.getSize())
|
if (data.length > _property.getSize()) {
|
||||||
{
|
byte[] tmp = new byte[_property.getSize()];
|
||||||
byte[] tmp = new byte[ _property.getSize() ];
|
|
||||||
|
|
||||||
System.arraycopy(data, 0, tmp, 0, tmp.length);
|
System.arraycopy(data, 0, tmp, 0, tmp.length);
|
||||||
data = tmp;
|
data = tmp;
|
||||||
@ -347,30 +330,23 @@ public class POIFSDocument
|
|||||||
output = new ByteArrayOutputStream();
|
output = new ByteArrayOutputStream();
|
||||||
HexDump.dump(data, 0, output, 0);
|
HexDump.dump(data, 0, output, 0);
|
||||||
result = output.toString();
|
result = output.toString();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
result = "<NO DATA>";
|
result = "<NO DATA>";
|
||||||
}
|
}
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
result = e.getMessage();
|
result = e.getMessage();
|
||||||
}
|
}
|
||||||
results[ 0 ] = result;
|
results[0] = result;
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an Iterator of objects, some of which may implement
|
* Get an Iterator of objects, some of which may implement POIFSViewable
|
||||||
* POIFSViewable
|
|
||||||
*
|
*
|
||||||
* @return an Iterator; may not be null, but may have an empty
|
* @return an Iterator; may not be null, but may have an empty back end
|
||||||
* back end store
|
* store
|
||||||
*/
|
*/
|
||||||
|
public Iterator getViewableIterator() {
|
||||||
public Iterator getViewableIterator()
|
|
||||||
{
|
|
||||||
return Collections.EMPTY_LIST.iterator();
|
return Collections.EMPTY_LIST.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,12 +354,10 @@ public class POIFSDocument
|
|||||||
* Give viewers a hint as to whether to call getViewableArray or
|
* Give viewers a hint as to whether to call getViewableArray or
|
||||||
* getViewableIterator
|
* getViewableIterator
|
||||||
*
|
*
|
||||||
* @return true if a viewer should call getViewableArray, false if
|
* @return <code>true</code> if a viewer should call getViewableArray,
|
||||||
* a viewer should call getViewableIterator
|
* <code>false</code> if a viewer should call getViewableIterator
|
||||||
*/
|
*/
|
||||||
|
public boolean preferArray() {
|
||||||
public boolean preferArray()
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,39 +367,29 @@ public class POIFSDocument
|
|||||||
*
|
*
|
||||||
* @return short description
|
* @return short description
|
||||||
*/
|
*/
|
||||||
|
public String getShortDescription() {
|
||||||
public String getShortDescription()
|
|
||||||
{
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
buffer.append("Document: \"").append(_property.getName())
|
buffer.append("Document: \"").append(_property.getName()).append("\"");
|
||||||
.append("\"");
|
|
||||||
buffer.append(" size = ").append(getSize());
|
buffer.append(" size = ").append(getSize());
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ********** END begin implementation of POIFSViewable ********** */
|
/* ********** END begin implementation of POIFSViewable ********** */
|
||||||
private class SmallBlockStore
|
private static final class SmallBlockStore {
|
||||||
{
|
|
||||||
private SmallDocumentBlock[] smallBlocks;
|
private SmallDocumentBlock[] smallBlocks;
|
||||||
private POIFSDocumentPath path;
|
private final POIFSDocumentPath path;
|
||||||
private String name;
|
private final String name;
|
||||||
private int size;
|
private final int size;
|
||||||
private POIFSWriterListener writer;
|
private final POIFSWriterListener writer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param blocks blocks to construct the store from
|
* @param blocks blocks to construct the store from
|
||||||
*/
|
*/
|
||||||
|
SmallBlockStore(SmallDocumentBlock[] blocks) {
|
||||||
SmallBlockStore(final Object [] blocks)
|
smallBlocks = (SmallDocumentBlock[]) blocks.clone();
|
||||||
{
|
|
||||||
smallBlocks = new SmallDocumentBlock[ blocks.length ];
|
|
||||||
for (int j = 0; j < blocks.length; j++)
|
|
||||||
{
|
|
||||||
smallBlocks[ j ] = ( SmallDocumentBlock ) blocks[ j ];
|
|
||||||
}
|
|
||||||
this.path = null;
|
this.path = null;
|
||||||
this.name = null;
|
this.name = null;
|
||||||
this.size = -1;
|
this.size = -1;
|
||||||
@ -433,19 +397,15 @@ public class POIFSDocument
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a small block store that will be written
|
* Constructor for a small block store that will be written later
|
||||||
* later
|
|
||||||
*
|
*
|
||||||
* @param path path of the document
|
* @param path path of the document
|
||||||
* @param name name of the document
|
* @param name name of the document
|
||||||
* @param size length 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
|
||||||
*/
|
*/
|
||||||
|
SmallBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
|
||||||
SmallBlockStore(final POIFSDocumentPath path, final String name,
|
smallBlocks = new SmallDocumentBlock[0];
|
||||||
final int size, final POIFSWriterListener writer)
|
|
||||||
{
|
|
||||||
smallBlocks = new SmallDocumentBlock[ 0 ];
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.size = size;
|
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() {
|
||||||
boolean isValid()
|
return smallBlocks.length > 0 || writer != null;
|
||||||
{
|
|
||||||
return ((smallBlocks.length > 0) || (writer != null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the SmallDocumentBlocks
|
* @return the SmallDocumentBlocks
|
||||||
*/
|
*/
|
||||||
|
SmallDocumentBlock[] getBlocks() {
|
||||||
|
if (isValid() && writer != null) {
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
|
||||||
|
DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
|
||||||
|
|
||||||
BlockWritable [] getBlocks()
|
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
|
||||||
{
|
smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(), size);
|
||||||
if (isValid() && (writer != null))
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream stream =
|
|
||||||
new ByteArrayOutputStream(size);
|
|
||||||
DocumentOutputStream dstream =
|
|
||||||
new DocumentOutputStream(stream, size);
|
|
||||||
|
|
||||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
|
|
||||||
path, name, size));
|
|
||||||
smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(),
|
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
return smallBlocks;
|
return smallBlocks;
|
||||||
}
|
}
|
||||||
} // end private class SmallBlockStore
|
} // end private class SmallBlockStore
|
||||||
|
|
||||||
private class BigBlockStore
|
private static final class BigBlockStore {
|
||||||
{
|
|
||||||
private DocumentBlock[] bigBlocks;
|
private DocumentBlock[] bigBlocks;
|
||||||
private POIFSDocumentPath path;
|
private final POIFSDocumentPath path;
|
||||||
private String name;
|
private final String name;
|
||||||
private int size;
|
private final int size;
|
||||||
private POIFSWriterListener writer;
|
private final POIFSWriterListener writer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param blocks the blocks making up the store
|
* @param blocks the blocks making up the store
|
||||||
*
|
|
||||||
* @exception IOException on I/O error
|
|
||||||
*/
|
*/
|
||||||
|
BigBlockStore(DocumentBlock[] blocks) {
|
||||||
BigBlockStore(final Object [] blocks)
|
bigBlocks = (DocumentBlock[]) blocks.clone();
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
bigBlocks = new DocumentBlock[ blocks.length ];
|
|
||||||
for (int j = 0; j < blocks.length; j++)
|
|
||||||
{
|
|
||||||
if (blocks[ j ] instanceof DocumentBlock)
|
|
||||||
{
|
|
||||||
bigBlocks[ j ] = ( DocumentBlock ) blocks[ j ];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bigBlocks[ j ] =
|
|
||||||
new DocumentBlock(( RawDataBlock ) blocks[ j ]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.path = null;
|
this.path = null;
|
||||||
this.name = null;
|
this.name = null;
|
||||||
this.size = -1;
|
this.size = -1;
|
||||||
@ -522,20 +455,15 @@ public class POIFSDocument
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a big block store that will be written
|
* Constructor for a big block store that will be written later
|
||||||
* later
|
|
||||||
*
|
*
|
||||||
* @param path path of the document
|
* @param path path of the document
|
||||||
* @param name name of the document
|
* @param name name of the document
|
||||||
* @param size length of the document
|
* @param size length of the document
|
||||||
* @param writer the object that will eventually write the
|
* @param writer the object that will eventually write the document
|
||||||
* document
|
|
||||||
*/
|
*/
|
||||||
|
BigBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
|
||||||
BigBlockStore(final POIFSDocumentPath path, final String name,
|
bigBlocks = new DocumentBlock[0];
|
||||||
final int size, final POIFSWriterListener writer)
|
|
||||||
{
|
|
||||||
bigBlocks = new DocumentBlock[ 0 ];
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.size = size;
|
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() {
|
||||||
boolean isValid()
|
return bigBlocks.length > 0 || writer != null;
|
||||||
{
|
|
||||||
return ((bigBlocks.length > 0) || (writer != null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the DocumentBlocks
|
* @return the DocumentBlocks
|
||||||
*/
|
*/
|
||||||
|
DocumentBlock[] getBlocks() {
|
||||||
|
if (isValid() && writer != null) {
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
|
||||||
|
DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
|
||||||
|
|
||||||
DocumentBlock [] getBlocks()
|
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
|
||||||
{
|
|
||||||
if (isValid() && (writer != null))
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream stream =
|
|
||||||
new ByteArrayOutputStream(size);
|
|
||||||
DocumentOutputStream dstream =
|
|
||||||
new DocumentOutputStream(stream, size);
|
|
||||||
|
|
||||||
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
|
|
||||||
path, name, size));
|
|
||||||
bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
|
bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
|
||||||
}
|
}
|
||||||
return bigBlocks;
|
return bigBlocks;
|
||||||
@ -575,32 +495,18 @@ public class POIFSDocument
|
|||||||
* write the blocks to a stream
|
* write the blocks to a stream
|
||||||
*
|
*
|
||||||
* @param stream the stream to which the data is to be written
|
* @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)
|
writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
|
||||||
throws IOException
|
dstream.writeFiller(countBlocks() * POIFSConstants.BIG_BLOCK_SIZE,
|
||||||
{
|
DocumentBlock.getFillByte());
|
||||||
if (isValid())
|
} else {
|
||||||
{
|
for (int k = 0; k < bigBlocks.length; k++) {
|
||||||
if (writer != null)
|
bigBlocks[k].writeBlocks(stream);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -609,25 +515,16 @@ public class POIFSDocument
|
|||||||
/**
|
/**
|
||||||
* @return number of big blocks making up this document
|
* @return number of big blocks making up this document
|
||||||
*/
|
*/
|
||||||
|
int countBlocks() {
|
||||||
|
|
||||||
int countBlocks()
|
if (isValid()) {
|
||||||
{
|
if (writer == null) {
|
||||||
int rval = 0;
|
return bigBlocks.length;
|
||||||
|
}
|
||||||
if (isValid())
|
return (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
|
||||||
{
|
|
||||||
if (writer != null)
|
|
||||||
{
|
|
||||||
rval = (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
|
|
||||||
/ POIFSConstants.BIG_BLOCK_SIZE;
|
/ POIFSConstants.BIG_BLOCK_SIZE;
|
||||||
}
|
}
|
||||||
else
|
return 0;
|
||||||
{
|
|
||||||
rval = bigBlocks.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
}
|
}
|
||||||
} // end private class BigBlockStore
|
} // 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
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,30 +15,26 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.storage;
|
package org.apache.poi.poifs.storage;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.apache.poi.poifs.common.POIFSConstants;
|
import org.apache.poi.poifs.common.POIFSConstants;
|
||||||
import org.apache.poi.util.IOUtils;
|
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.
|
* A block of document data.
|
||||||
*
|
*
|
||||||
* @author Marc Johnson (mjohnson at apache dot org)
|
* @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 static final byte _default_value = ( byte ) 0xFF;
|
||||||
private byte[] _data;
|
private byte[] _data;
|
||||||
private int _bytes_read;
|
private int _bytes_read;
|
||||||
@ -161,45 +156,10 @@ public class DocumentBlock
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static DataInputBlock getDataInputBlock(DocumentBlock[] blocks, int offset) {
|
||||||
* read data from an array of DocumentBlocks
|
int firstBlockIndex = offset >> BLOCK_SHIFT;
|
||||||
*
|
int firstBlockOffset= offset & BLOCK_MASK;
|
||||||
* @param blocks the blocks to read from
|
return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ********** START extension of BigBlock ********** */
|
/* ********** START extension of BigBlock ********** */
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,12 +15,14 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.storage;
|
package org.apache.poi.poifs.storage;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.poifs.common.POIFSConstants;
|
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)
|
* @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 byte[] _data;
|
||||||
private static final byte _default_fill = ( byte ) 0xff;
|
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 =
|
private static final int _blocks_per_big_block =
|
||||||
POIFSConstants.BIG_BLOCK_SIZE / _block_size;
|
POIFSConstants.BIG_BLOCK_SIZE / _block_size;
|
||||||
|
|
||||||
@ -178,46 +180,10 @@ public class SmallDocumentBlock
|
|||||||
return sdbs;
|
return sdbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static DataInputBlock getDataInputBlock(SmallDocumentBlock[] blocks, int offset) {
|
||||||
* read data from an array of SmallDocumentBlocks
|
int firstBlockIndex = offset >> BLOCK_SHIFT;
|
||||||
*
|
int firstBlockOffset= offset & BLOCK_MASK;
|
||||||
* @param blocks the blocks to read from
|
return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 Marc Johnson (mjohnson at apache dot org)
|
||||||
*@author Andrew Oliver (acoliver 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() {
|
private LittleEndian() {
|
||||||
// no instances of this class
|
// no instances of this class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a short value from a byte array
|
* 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
|
*@param offset a starting offset into the byte array
|
||||||
*@return the short (16-bit) value
|
*@return the short (16-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static short getShort(byte[] data, int offset) {
|
||||||
public static short getShort(final byte[] data, final int offset) {
|
int b0 = data[offset] & 0xFF;
|
||||||
return (short) getNumber(data, offset, SHORT_SIZE);
|
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
|
*@param offset a starting offset into the byte array
|
||||||
*@return the unsigned short (16-bit) value in an integer
|
*@return the unsigned short (16-bit) value in an integer
|
||||||
*/
|
*/
|
||||||
public static int getUShort(final byte[] data, final int offset) {
|
public static int getUShort(byte[] data, int offset) {
|
||||||
short num = (short) getNumber(data, offset, SHORT_SIZE);
|
int b0 = data[offset] & 0xFF;
|
||||||
int retNum;
|
int b1 = data[offset+1] & 0xFF;
|
||||||
if (num < 0) {
|
return (b1 << 8) + (b0 << 0);
|
||||||
retNum = (Short.MAX_VALUE + 1) * 2 + num;
|
|
||||||
} else {
|
|
||||||
retNum = num;
|
|
||||||
}
|
}
|
||||||
return retNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get a short array from a byte array.
|
|
||||||
*
|
|
||||||
*@param data Description of the Parameter
|
|
||||||
*@param offset Description of the Parameter
|
|
||||||
*@param size Description of the Parameter
|
|
||||||
*@return The simpleShortArray value
|
|
||||||
*/
|
|
||||||
public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) {
|
|
||||||
short[] results = new short[size];
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
results[i] = getShort(data, offset + 2 + (i * 2));
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get a short array from a byte array. The short array is assumed to start
|
|
||||||
* with a word describing the length of the array.
|
|
||||||
*
|
|
||||||
*@param data Description of the Parameter
|
|
||||||
*@param offset Description of the Parameter
|
|
||||||
*@return The shortArray value
|
|
||||||
*/
|
|
||||||
public static short[] getShortArray(final byte[] data, final int offset) {
|
|
||||||
int size = (int) getNumber(data, offset, SHORT_SIZE);
|
|
||||||
short[] results = getSimpleShortArray(data, offset, size);
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a short value from the beginning of a byte array
|
* 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
|
*@param data the byte array
|
||||||
*@return the short (16-bit) value
|
*@return the short (16-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static short getShort(byte[] data) {
|
||||||
public static short getShort(final byte[] data) {
|
|
||||||
return getShort(data, 0);
|
return getShort(data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get an unsigned short value from the beginning of a byte array
|
* get an unsigned short value from the beginning of a byte array
|
||||||
*
|
*
|
||||||
*@param data the byte array
|
*@param data the byte array
|
||||||
*@return the unsigned short (16-bit) value in an int
|
*@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);
|
return getUShort(data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get an int value from a byte array
|
* 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
|
*@param offset a starting offset into the byte array
|
||||||
*@return the int (32-bit) value
|
*@return the int (32-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static int getInt(byte[] data, int offset) {
|
||||||
public static int getInt(final byte[] data, final int offset) {
|
int i=offset;
|
||||||
return (int) getNumber(data, offset, INT_SIZE);
|
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
|
*@param data the byte array
|
||||||
*@return the int (32-bit) value
|
*@return the int (32-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static int getInt(byte[] data) {
|
||||||
public static int getInt(final byte[] data) {
|
|
||||||
return getInt(data, 0);
|
return getInt(data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,15 +116,9 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
*@param offset a starting offset into the byte array
|
*@param offset a starting offset into the byte array
|
||||||
*@return the unsigned int (32-bit) value in a long
|
*@return the unsigned int (32-bit) value in a long
|
||||||
*/
|
*/
|
||||||
public static long getUInt(final byte[] data, final int offset) {
|
public static long getUInt(byte[] data, int offset) {
|
||||||
int num = (int) getNumber(data, offset, INT_SIZE);
|
long retNum = getInt(data, offset);
|
||||||
long retNum;
|
return retNum & 0x00FFFFFFFF;
|
||||||
if (num < 0) {
|
|
||||||
retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
|
|
||||||
} else {
|
|
||||||
retNum = num;
|
|
||||||
}
|
|
||||||
return retNum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,7 +127,7 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
*@param data the byte array
|
*@param data the byte array
|
||||||
*@return the unsigned int (32-bit) value in a long
|
*@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);
|
return getUInt(data,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,24 +138,16 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
*@param offset a starting offset into the byte array
|
*@param offset a starting offset into the byte array
|
||||||
*@return the long (64-bit) value
|
*@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) {
|
for (int j = offset + LONG_SIZE - 1; j >= offset; j--) {
|
||||||
return getNumber(data, offset, LONG_SIZE);
|
result <<= 8;
|
||||||
|
result |= 0xff & data[j];
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
/**
|
|
||||||
* get a long value from the beginning of a byte array
|
|
||||||
*
|
|
||||||
*@param data the byte array
|
|
||||||
*@return the long (64-bit) value
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static long getLong(final byte[] data) {
|
|
||||||
return getLong(data, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a double value from a byte array, reads it in little endian format
|
* get a double value from a byte array, reads it in little endian format
|
||||||
* then converts the resulting revolting IEEE 754 (curse them) floating
|
* 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
|
*@param offset a starting offset into the byte array
|
||||||
*@return the double (64-bit) value
|
*@return the double (64-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static double getDouble(byte[] data, int offset) {
|
||||||
public static double getDouble(final byte[] data, final int offset) {
|
return Double.longBitsToDouble(getLong(data, offset));
|
||||||
return Double.longBitsToDouble(getNumber(data, offset, DOUBLE_SIZE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get a double value from the beginning of a byte array
|
|
||||||
*
|
|
||||||
*@param data the byte array
|
|
||||||
*@return the double (64-bit) value
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static double getDouble(final byte[] data) {
|
|
||||||
return getDouble(data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* put a short value into a byte array
|
* 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 offset a starting offset into the byte array
|
||||||
*@param value the short (16-bit) value
|
*@param value the short (16-bit) value
|
||||||
*/
|
*/
|
||||||
public static void putShort(final byte[] data, final int offset,
|
public static void putShort(byte[] data, int offset, short value) {
|
||||||
final short value) {
|
int i = offset;
|
||||||
putNumber(data, offset, value, SHORT_SIZE);
|
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
|
* Added for consistency with other put~() methods
|
||||||
*/
|
*/
|
||||||
public static void putByte(byte[] data, int offset, int value) {
|
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
|
* @exception ArrayIndexOutOfBoundsException may be thrown
|
||||||
*/
|
*/
|
||||||
public static void putUShort(final byte[] data, final int offset,
|
public static void putUShort(byte[] data, int offset, int value) {
|
||||||
final int value)
|
int i = offset;
|
||||||
{
|
data[i++] = (byte)((value >>> 0) & 0xFF);
|
||||||
putNumber(data, offset, value, SHORT_SIZE);
|
data[i++] = (byte)((value >>> 8) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,8 +206,7 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
*@param data the byte array
|
*@param data the byte array
|
||||||
*@param value the short (16-bit) value
|
*@param value the short (16-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static void putShort(byte[] data, short value) {
|
||||||
public static void putShort(final byte[] data, final short value) {
|
|
||||||
putShort(data, 0, 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 offset a starting offset into the byte array
|
||||||
*@param value the int (32-bit) value
|
*@param value the int (32-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static void putInt(byte[] data, int offset, int value) {
|
||||||
public static void putInt(final byte[] data, final int offset,
|
int i = offset;
|
||||||
final int value) {
|
data[i++] = (byte)((value >>> 0) & 0xFF);
|
||||||
putNumber(data, offset, value, INT_SIZE);
|
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 data the byte array
|
||||||
*@param value the int (32-bit) value
|
*@param value the int (32-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static void putInt(byte[] data, int value) {
|
||||||
public static void putInt(final byte[] data, final int value) {
|
|
||||||
putInt(data, 0, 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 offset a starting offset into the byte array
|
||||||
*@param value the long (64-bit) value
|
*@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,
|
for (int j = offset; j < limit; j++) {
|
||||||
final long value) {
|
data[j] = (byte) (v & 0xFF);
|
||||||
putNumber(data, offset, value, LONG_SIZE);
|
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 offset a starting offset into the byte array
|
||||||
*@param value the double (64-bit) value
|
*@param value the double (64-bit) value
|
||||||
*/
|
*/
|
||||||
|
public static void putDouble(byte[] data, int offset, double value) {
|
||||||
public static void putDouble(final byte[] data, final int offset,
|
|
||||||
final double value) {
|
|
||||||
// Excel likes NaN to be a specific value.
|
// Excel likes NaN to be a specific value.
|
||||||
if (Double.isNaN(value))
|
if (Double.isNaN(value)) {
|
||||||
putNumber(data, offset, -276939487313920L, DOUBLE_SIZE);
|
putLong(data, offset, -276939487313920L);
|
||||||
else
|
} else {
|
||||||
putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE);
|
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)
|
*@author Marc Johnson (mjohnson at apache dot org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static final class BufferUnderrunException extends IOException {
|
public static final class BufferUnderrunException extends IOException {
|
||||||
|
|
||||||
BufferUnderrunException() {
|
BufferUnderrunException() {
|
||||||
@ -376,12 +289,10 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
/**
|
/**
|
||||||
* get a short value from an InputStream
|
* get a short value from an InputStream
|
||||||
*
|
*
|
||||||
*@param stream the InputStream from which the short
|
*@param stream the InputStream from which the short is to be read
|
||||||
* is to be read
|
|
||||||
*@return the short (16-bit) value
|
*@return the short (16-bit) value
|
||||||
*@exception IOException will be propagated back to the caller
|
*@exception IOException will be propagated back to the caller
|
||||||
*@exception BufferUnderrunException if the stream cannot provide enough
|
*@exception BufferUnderrunException if the stream cannot provide enough bytes
|
||||||
* bytes
|
|
||||||
*/
|
*/
|
||||||
public static short readShort(InputStream stream) throws IOException, BufferUnderrunException {
|
public static short readShort(InputStream stream) throws IOException, BufferUnderrunException {
|
||||||
|
|
||||||
@ -395,21 +306,19 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
if ((ch1 | ch2) < 0) {
|
if ((ch1 | ch2) < 0) {
|
||||||
throw new BufferUnderrunException();
|
throw new BufferUnderrunException();
|
||||||
}
|
}
|
||||||
return ((ch2 << 8) + (ch1 << 0));
|
return (ch2 << 8) + (ch1 << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get an int value from an InputStream
|
* get an int value from an InputStream
|
||||||
*
|
*
|
||||||
*@param stream the InputStream from which the int is
|
*@param stream the InputStream from which the int is to be read
|
||||||
* to be read
|
* @return the int (32-bit) value
|
||||||
*@return the int (32-bit) value
|
* @exception IOException will be propagated back to the caller
|
||||||
*@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 int readInt(final InputStream stream)
|
public static int readInt(InputStream stream)
|
||||||
throws IOException, BufferUnderrunException {
|
throws IOException, BufferUnderrunException {
|
||||||
int ch1 = stream.read();
|
int ch1 = stream.read();
|
||||||
int ch2 = stream.read();
|
int ch2 = stream.read();
|
||||||
@ -418,22 +327,19 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
if ((ch1 | ch2 | ch3 | ch4) < 0) {
|
if ((ch1 | ch2 | ch3 | ch4) < 0) {
|
||||||
throw new BufferUnderrunException();
|
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
|
* get a long value from an InputStream
|
||||||
*
|
*
|
||||||
*@param stream the InputStream from which the long
|
* @param stream the InputStream from which the long is to be read
|
||||||
* is to be read
|
* @return the long (64-bit) value
|
||||||
*@return the long (64-bit) value
|
* @exception IOException will be propagated back to the caller
|
||||||
*@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 long readLong(InputStream stream)
|
||||||
public static long readLong(final InputStream stream)
|
|
||||||
throws IOException, BufferUnderrunException {
|
throws IOException, BufferUnderrunException {
|
||||||
int ch1 = stream.read();
|
int ch1 = stream.read();
|
||||||
int ch2 = stream.read();
|
int ch2 = stream.read();
|
||||||
@ -458,114 +364,44 @@ public final class LittleEndian implements LittleEndianConsts {
|
|||||||
(ch1 << 0);
|
(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
|
* Convert an 'unsigned' byte to an integer. ie, don't carry across the
|
||||||
* sign.
|
* sign.
|
||||||
*
|
*
|
||||||
*@param b Description of the Parameter
|
* @param b Description of the Parameter
|
||||||
*@return Description of the Return Value
|
* @return Description of the Return Value
|
||||||
*/
|
*/
|
||||||
public static int ubyteToInt(byte b) {
|
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.
|
* get the unsigned value of a byte.
|
||||||
*
|
*
|
||||||
*@param data the byte array.
|
* @param data the byte array.
|
||||||
*@param offset a starting offset into the byte array.
|
* @param offset a starting offset into the byte array.
|
||||||
*@return the unsigned value of the byte as a 32 bit integer
|
* @return the unsigned value of the byte as a 32 bit integer
|
||||||
*/
|
*/
|
||||||
public static int getUnsignedByte(final byte[] data, final int offset) {
|
public static int getUnsignedByte(byte[] data, int offset) {
|
||||||
return (int) getNumber(data, offset, BYTE_SIZE);
|
return data[offset] & 0xFF;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy a portion of a byte array
|
* Copy a portion of a byte array
|
||||||
*
|
*
|
||||||
*@param data the original byte array
|
* @param data the original byte array
|
||||||
*@param offset Where to start copying from.
|
* @param offset Where to start copying from.
|
||||||
*@param size Number of bytes to copy.
|
* @param size Number of bytes to copy.
|
||||||
*@return The byteArray value
|
* @return The byteArray value
|
||||||
*@throws IndexOutOfBoundsException - if copying would cause access of
|
* @throws IndexOutOfBoundsException - if copying would cause access of
|
||||||
* data outside array bounds.
|
* 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];
|
byte[] copy = new byte[size];
|
||||||
System.arraycopy(data, offset, copy, 0, size);
|
System.arraycopy(data, offset, copy, 0, size);
|
||||||
|
|
||||||
return copy;
|
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
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
public interface LittleEndianInput {
|
public interface LittleEndianInput {
|
||||||
|
int available();
|
||||||
byte readByte();
|
byte readByte();
|
||||||
int readUByte();
|
int readUByte();
|
||||||
short readShort();
|
short readShort();
|
||||||
@ -30,6 +31,4 @@ public interface LittleEndianInput {
|
|||||||
double readDouble();
|
double readDouble();
|
||||||
void readFully(byte[] buf);
|
void readFully(byte[] buf);
|
||||||
void readFully(byte[] buf, int off, int len);
|
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;
|
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
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
@ -29,7 +33,13 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
|||||||
public LittleEndianInputStream(InputStream is) {
|
public LittleEndianInputStream(InputStream is) {
|
||||||
super(is);
|
super(is);
|
||||||
}
|
}
|
||||||
|
public int available() {
|
||||||
|
try {
|
||||||
|
return super.available();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
public byte readByte() {
|
public byte readByte() {
|
||||||
return (byte)readUByte();
|
return (byte)readUByte();
|
||||||
}
|
}
|
||||||
@ -131,34 +141,4 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
|||||||
buf[i] = (byte) ch;
|
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.io.UnsupportedEncodingException;
|
||||||
import java.text.FieldPosition;
|
import java.text.FieldPosition;
|
||||||
import java.text.NumberFormat;
|
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 Andrew C. Oliver
|
||||||
*@author Sergei Kozello (sergeikozello at mail.ru)
|
*@author Sergei Kozello (sergeikozello at mail.ru)
|
||||||
@ -84,64 +89,11 @@ public class StringUtil {
|
|||||||
* @param string the byte array to be converted
|
* @param string the byte array to be converted
|
||||||
* @return the converted string
|
* @return the converted string
|
||||||
*/
|
*/
|
||||||
public static String getFromUnicodeLE(final byte[] string) {
|
public static String getFromUnicodeLE(byte[] string) {
|
||||||
if(string.length == 0) { return ""; }
|
if(string.length == 0) { return ""; }
|
||||||
return getFromUnicodeLE(string, 0, string.length / 2);
|
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
|
* Read 8 bit data (in ISO-8859-1 codepage) into a (unicode) Java
|
||||||
* String and return.
|
* String and return.
|
||||||
@ -163,6 +115,52 @@ public class StringUtil {
|
|||||||
throw new RuntimeException(e);
|
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
|
* 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);
|
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.
|
* Apply printf() like formatting to a string.
|
||||||
* Primarily used for logging.
|
* Primarily used for logging.
|
||||||
|
@ -100,6 +100,7 @@ public final class AllRecordTests {
|
|||||||
result.addTestSuite(TestSheetPropertiesRecord.class);
|
result.addTestSuite(TestSheetPropertiesRecord.class);
|
||||||
result.addTestSuite(TestSharedFormulaRecord.class);
|
result.addTestSuite(TestSharedFormulaRecord.class);
|
||||||
result.addTestSuite(TestStringRecord.class);
|
result.addTestSuite(TestStringRecord.class);
|
||||||
|
result.addTestSuite(TestStyleRecord.class);
|
||||||
result.addTestSuite(TestSubRecord.class);
|
result.addTestSuite(TestSubRecord.class);
|
||||||
result.addTestSuite(TestSupBookRecord.class);
|
result.addTestSuite(TestSupBookRecord.class);
|
||||||
result.addTestSuite(TestTableRecord.class);
|
result.addTestSuite(TestTableRecord.class);
|
||||||
|
@ -37,7 +37,7 @@ public final class TestCommonObjectDataSubRecord extends TestCase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public void testLoad() {
|
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( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX, record.getObjectType());
|
||||||
assertEquals((short) 1, record.getObjectId());
|
assertEquals((short) 1, record.getObjectId());
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.util.HexRead;
|
import org.apache.poi.util.HexRead;
|
||||||
@ -37,33 +38,43 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
|
|||||||
public void testStore() {
|
public void testStore() {
|
||||||
|
|
||||||
byte[] src = hr(data1);
|
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));
|
RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, src);
|
||||||
in.nextRecord();
|
|
||||||
|
|
||||||
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length-4);
|
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length);
|
||||||
|
|
||||||
byte[] ser = record1.serialize();
|
byte[] ser = record1.serialize();
|
||||||
|
|
||||||
RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));
|
RecordInputStream in2 = TestcaseRecordInputStream.create(ser);
|
||||||
in2.nextRecord();
|
|
||||||
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
|
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
|
||||||
|
|
||||||
assertTrue(Arrays.equals(src, ser));
|
confirmData(src, ser);
|
||||||
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
|
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
|
||||||
|
|
||||||
byte[] ser2 = record1.serialize();
|
byte[] ser2 = record1.serialize();
|
||||||
assertTrue(Arrays.equals(ser, ser2));
|
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() {
|
public void testCreate() {
|
||||||
|
|
||||||
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord();
|
EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord();
|
||||||
|
|
||||||
byte[] ser = record1.serialize();
|
byte[] ser = record1.serialize();
|
||||||
RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));
|
RecordInputStream in2 = TestcaseRecordInputStream.create(ser);
|
||||||
in2.nextRecord();
|
|
||||||
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
|
EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);
|
||||||
|
|
||||||
assertEquals(record1.getOLEClassName(), record2.getOLEClassName());
|
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).
|
* taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).
|
||||||
*/
|
*/
|
||||||
private static final byte[] data45912 = hr(
|
private static final byte[] data45912 = hr(
|
||||||
"09 00 14 00 " +
|
|
||||||
"12 00 0B 00 F8 02 88 04 3B 00 " +
|
"12 00 0B 00 F8 02 88 04 3B 00 " +
|
||||||
"00 00 00 01 00 00 00 01 " +
|
"00 00 00 01 00 00 00 01 " +
|
||||||
"00 00");
|
"00 00");
|
||||||
|
|
||||||
public void testCameraTool_bug45912() {
|
public void testCameraTool_bug45912() {
|
||||||
byte[] data = data45912;
|
byte[] data = data45912;
|
||||||
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
|
RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);
|
||||||
in.nextRecord();
|
|
||||||
|
|
||||||
EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length-4);
|
EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);
|
||||||
byte[] ser2 = rec.serialize();
|
byte[] ser2 = rec.serialize();
|
||||||
assertTrue(Arrays.equals(data, ser2));
|
confirmData(data, ser2);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] hr(String string) {
|
private static byte[] hr(String string) {
|
||||||
|
@ -119,7 +119,6 @@ public final class TestFormulaRecord extends TestCase {
|
|||||||
public void testWithConcat() {
|
public void testWithConcat() {
|
||||||
// =CHOOSE(2,A2,A3,A4)
|
// =CHOOSE(2,A2,A3,A4)
|
||||||
byte[] data = {
|
byte[] data = {
|
||||||
6, 0, 68, 0,
|
|
||||||
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
|
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
|
||||||
64, 0, 0, 12, 0, 12, -4, 46, 0,
|
64, 0, 0, 12, 0, 12, -4, 46, 0,
|
||||||
30, 2, 0, // Int - 2
|
30, 2, 0, // Int - 2
|
||||||
@ -134,8 +133,7 @@ public final class TestFormulaRecord extends TestCase {
|
|||||||
25, 8, 3, 0, // Attr
|
25, 8, 3, 0, // Attr
|
||||||
66, 4, 100, 0 // CHOOSE
|
66, 4, 100, 0 // CHOOSE
|
||||||
};
|
};
|
||||||
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
|
RecordInputStream inp = TestcaseRecordInputStream.create(FormatRecord.sid, data);
|
||||||
inp.nextRecord();
|
|
||||||
|
|
||||||
FormulaRecord fr = new FormulaRecord(inp);
|
FormulaRecord fr = new FormulaRecord(inp);
|
||||||
|
|
||||||
|
@ -239,8 +239,7 @@ public final class TestHyperlinkRecord extends TestCase {
|
|||||||
RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data);
|
RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data);
|
||||||
HyperlinkRecord link = new HyperlinkRecord(is);
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
byte[] bytes1 = link.serialize();
|
byte[] bytes1 = link.serialize();
|
||||||
is = new RecordInputStream(new ByteArrayInputStream(bytes1));
|
is = TestcaseRecordInputStream.create(bytes1);
|
||||||
is.nextRecord();
|
|
||||||
link = new HyperlinkRecord(is);
|
link = new HyperlinkRecord(is);
|
||||||
byte[] bytes2 = link.serialize();
|
byte[] bytes2 = link.serialize();
|
||||||
assertEquals(bytes1.length, bytes2.length);
|
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.Ptg;
|
||||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
@ -59,7 +60,7 @@ public final class TestSharedFormulaRecord extends TestCase {
|
|||||||
*/
|
*/
|
||||||
public void testConvertSharedFormulasOperandClasses_bug45123() {
|
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();
|
int encodedLen = in.readUShort();
|
||||||
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
|
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() {
|
public void testLoad() {
|
||||||
RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
|
RecordInputStream in = TestcaseRecordInputStream.create(data);
|
||||||
in.nextRecord();
|
|
||||||
TextObjectRecord record = new TextObjectRecord(in);
|
TextObjectRecord record = new TextObjectRecord(in);
|
||||||
|
|
||||||
|
|
||||||
assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment());
|
assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment());
|
||||||
assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment());
|
assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment());
|
||||||
assertEquals(true, record.isTextLocked());
|
assertEquals(true, record.isTextLocked());
|
||||||
|
@ -52,8 +52,7 @@ public final class TestTextObjectRecord extends TestCase {
|
|||||||
|
|
||||||
public void testRead() {
|
public void testRead() {
|
||||||
|
|
||||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
|
RecordInputStream is =TestcaseRecordInputStream.create(simpleData);
|
||||||
is.nextRecord();
|
|
||||||
TextObjectRecord record = new TextObjectRecord(is);
|
TextObjectRecord record = new TextObjectRecord(is);
|
||||||
|
|
||||||
assertEquals(TextObjectRecord.sid, record.getSid());
|
assertEquals(TextObjectRecord.sid, record.getSid());
|
||||||
@ -79,8 +78,7 @@ public final class TestTextObjectRecord extends TestCase {
|
|||||||
assertTrue(Arrays.equals(simpleData, ser));
|
assertTrue(Arrays.equals(simpleData, ser));
|
||||||
|
|
||||||
//read again
|
//read again
|
||||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));
|
RecordInputStream is = TestcaseRecordInputStream.create(simpleData);
|
||||||
is.nextRecord();
|
|
||||||
record = new TextObjectRecord(is);
|
record = new TextObjectRecord(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +99,7 @@ public final class TestTextObjectRecord extends TestCase {
|
|||||||
assertEquals(22, ser.length); // just the TXO record
|
assertEquals(22, ser.length); // just the TXO record
|
||||||
|
|
||||||
//read again
|
//read again
|
||||||
RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));
|
RecordInputStream is = TestcaseRecordInputStream.create(ser);
|
||||||
is.nextRecord();
|
|
||||||
record = new TextObjectRecord(is);
|
record = new TextObjectRecord(is);
|
||||||
assertEquals(0, record.getStr().length());
|
assertEquals(0, record.getStr().length());
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ import java.io.InputStream;
|
|||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
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
|
* 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
|
* Prepends a mock record identifier to the supplied data and opens a record input stream
|
||||||
*/
|
*/
|
||||||
public static RecordInputStream createWithFakeSid(byte[] data) {
|
public static LittleEndianInput createLittleEndian(byte[] data) {
|
||||||
return create(-5555, data);
|
return new LittleEndianByteArrayInputStream(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
public static RecordInputStream create(int sid, byte[] data) {
|
public static RecordInputStream create(int sid, byte[] data) {
|
||||||
|
@ -21,11 +21,12 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
|
||||||
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
||||||
import org.apache.poi.hssf.record.UnicodeString;
|
import org.apache.poi.hssf.record.UnicodeString;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
||||||
import org.apache.poi.util.HexRead;
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
@ -52,14 +53,15 @@ public final class TestConstantValueParser extends TestCase {
|
|||||||
public void testEncode() {
|
public void testEncode() {
|
||||||
int size = ConstantValueParser.getEncodedSize(SAMPLE_VALUES);
|
int size = ConstantValueParser.getEncodedSize(SAMPLE_VALUES);
|
||||||
byte[] data = new byte[size];
|
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)) {
|
if (!Arrays.equals(data, SAMPLE_ENCODING)) {
|
||||||
fail("Encoding differs");
|
fail("Encoding differs");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void testDecode() {
|
public void testDecode() {
|
||||||
RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SAMPLE_ENCODING);
|
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SAMPLE_ENCODING);
|
||||||
|
|
||||||
Object[] values = ConstantValueParser.parse(in, 4);
|
Object[] values = ConstantValueParser.parse(in, 4);
|
||||||
for (int i = 0; i < values.length; i++) {
|
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.TestcaseRecordInputStream;
|
||||||
import org.apache.poi.hssf.record.UnicodeString;
|
import org.apache.poi.hssf.record.UnicodeString;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
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.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
@ -54,9 +56,9 @@ public final class TestArrayPtg extends TestCase {
|
|||||||
*/
|
*/
|
||||||
public void testReadWriteTokenValueBytes() {
|
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(3, ptg.getColumnCount());
|
||||||
assertEquals(2, ptg.getRowCount());
|
assertEquals(2, ptg.getRowCount());
|
||||||
Object[][] values = ptg.getTokenArrayValues();
|
Object[][] values = ptg.getTokenArrayValues();
|
||||||
@ -70,7 +72,7 @@ public final class TestArrayPtg extends TestCase {
|
|||||||
assertEquals(new UnicodeString("FG"), values[1][2]);
|
assertEquals(new UnicodeString("FG"), values[1][2]);
|
||||||
|
|
||||||
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
|
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
|
||||||
ptg.writeTokenValueBytes(outBuf, 0);
|
ptg.writeTokenValueBytes(new LittleEndianByteArrayOutputStream(outBuf, 0));
|
||||||
|
|
||||||
if(outBuf[0] == 4) {
|
if(outBuf[0] == 4) {
|
||||||
throw new AssertionFailedError("Identified bug 42564b");
|
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.
|
* Excel stores array elements column by column. This test makes sure POI does the same.
|
||||||
*/
|
*/
|
||||||
public void testElementOrdering() {
|
public void testElementOrdering() {
|
||||||
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(3, ptg.getColumnCount());
|
||||||
assertEquals(2, ptg.getRowCount());
|
assertEquals(2, ptg.getRowCount());
|
||||||
|
|
||||||
@ -113,9 +115,9 @@ public final class TestArrayPtg extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testToFormulaString() {
|
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;
|
String actualFormula;
|
||||||
try {
|
try {
|
||||||
@ -146,7 +148,7 @@ public final class TestArrayPtg extends TestCase {
|
|||||||
// Force encoded operand class for tArray
|
// Force encoded operand class for tArray
|
||||||
fullData[0] = (byte) (ArrayPtg.sid + operandClass);
|
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);
|
Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in);
|
||||||
assertEquals(1, ptgs.length);
|
assertEquals(1, ptgs.length);
|
||||||
|
@ -21,9 +21,9 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import junit.framework.AssertionFailedError;
|
import junit.framework.AssertionFailedError;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
|
||||||
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
||||||
import org.apache.poi.util.HexRead;
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link AttrPtg}.
|
* Tests for {@link AttrPtg}.
|
||||||
@ -37,7 +37,7 @@ public final class TestAttrPtg extends AbstractPtgTestCase {
|
|||||||
*/
|
*/
|
||||||
public void testReserializeAttrChoose() {
|
public void testReserializeAttrChoose() {
|
||||||
byte[] data = HexRead.readFromString("19, 04, 03, 00, 08, 00, 11, 00, 1A, 00, 23, 00");
|
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);
|
Ptg[] ptgs = Ptg.readTokens(data.length, in);
|
||||||
byte[] data2 = new byte[data.length];
|
byte[] data2 = new byte[data.length];
|
||||||
try {
|
try {
|
||||||
|
@ -34,7 +34,7 @@ public final class TestFuncPtg extends TestCase {
|
|||||||
0,
|
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( "Len formula index is not 32(20H)", 0x20, ptg.getFunctionIndex() );
|
||||||
assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() );
|
assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() );
|
||||||
assertEquals( "Function Name", "LEN", ptg.getName() );
|
assertEquals( "Function Name", "LEN", ptg.getName() );
|
||||||
|
@ -23,10 +23,10 @@ import junit.framework.AssertionFailedError;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
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.record.TestcaseRecordInputStream;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link RefPtg}.
|
* Tests for {@link RefPtg}.
|
||||||
@ -94,7 +94,7 @@ public final class TestReferencePtg extends TestCase {
|
|||||||
0x2C, 33, 44, 55, 66,
|
0x2C, 33, 44, 55, 66,
|
||||||
};
|
};
|
||||||
public void testReadWrite_tRefN_bug45091() {
|
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);
|
Ptg[] ptgs = Ptg.readTokens(tRefN_data.length, in);
|
||||||
byte[] outData = new byte[5];
|
byte[] outData = new byte[5];
|
||||||
Ptg.serializePtgs(ptgs, outData, 0);
|
Ptg.serializePtgs(ptgs, outData, 0);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,17 +15,15 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.filesystem;
|
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.TestCase;
|
||||||
|
|
||||||
import junit.framework.*;
|
|
||||||
|
|
||||||
import org.apache.poi.poifs.property.DirectoryProperty;
|
import org.apache.poi.poifs.property.DirectoryProperty;
|
||||||
import org.apache.poi.poifs.property.DocumentProperty;
|
|
||||||
import org.apache.poi.poifs.storage.RawDataBlock;
|
import org.apache.poi.poifs.storage.RawDataBlock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,22 +32,9 @@ import org.apache.poi.poifs.storage.RawDataBlock;
|
|||||||
* @author Marc Johnson
|
* @author Marc Johnson
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TestDocumentInputStream
|
public final class TestDocumentInputStream extends TestCase {
|
||||||
extends TestCase
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
protected void setUp() throws Exception {
|
||||||
* Constructor TestDocumentInputStream
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public TestDocumentInputStream(String name)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(name);
|
|
||||||
int blocks = (_workbook_size + 511) / 512;
|
int blocks = (_workbook_size + 511) / 512;
|
||||||
|
|
||||||
_workbook_data = new byte[ 512 * blocks ];
|
_workbook_data = new byte[ 512 * blocks ];
|
||||||
@ -86,13 +70,8 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* test constructor
|
* test constructor
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testConstructor() throws IOException {
|
||||||
public void testConstructor()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
|
|
||||||
assertEquals(_workbook_size, stream.available());
|
assertEquals(_workbook_size, stream.available());
|
||||||
@ -100,13 +79,8 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* test available() behavior
|
* test available() behavior
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testAvailable() throws IOException {
|
||||||
public void testAvailable()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
|
|
||||||
assertEquals(_workbook_size, stream.available());
|
assertEquals(_workbook_size, stream.available());
|
||||||
@ -115,9 +89,7 @@ public class TestDocumentInputStream
|
|||||||
{
|
{
|
||||||
stream.available();
|
stream.available();
|
||||||
fail("Should have caught IOException");
|
fail("Should have caught IOException");
|
||||||
}
|
} catch (IllegalStateException ignored) {
|
||||||
catch (IOException ignored)
|
|
||||||
{
|
|
||||||
|
|
||||||
// as expected
|
// as expected
|
||||||
}
|
}
|
||||||
@ -125,13 +97,8 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* test mark/reset/markSupported.
|
* test mark/reset/markSupported.
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testMarkFunctions() throws IOException {
|
||||||
public void testMarkFunctions()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
byte[] buffer = new byte[ _workbook_size / 5 ];
|
byte[] buffer = new byte[ _workbook_size / 5 ];
|
||||||
|
|
||||||
@ -169,13 +136,8 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* test simple read method
|
* test simple read method
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testReadSingleByte() throws IOException {
|
||||||
public void testReadSingleByte()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
int remaining = _workbook_size;
|
int remaining = _workbook_size;
|
||||||
|
|
||||||
@ -205,13 +167,8 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test buffered read
|
* Test buffered read
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testBufferRead() throws IOException {
|
||||||
public void testBufferRead()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -275,23 +232,14 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test complex buffered read
|
* Test complex buffered read
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testComplexBufferRead() throws IOException {
|
||||||
public void testComplexBufferRead()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
stream.read(null, 0, 1);
|
stream.read(null, 0, 1);
|
||||||
fail("Should have caught NullPointerException");
|
fail("Should have caught NullPointerException");
|
||||||
}
|
} catch (IllegalArgumentException ignored) {
|
||||||
catch (NullPointerException ignored)
|
|
||||||
{
|
|
||||||
|
|
||||||
// as expected
|
// as expected
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,13 +339,8 @@ public class TestDocumentInputStream
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* test skip
|
* test skip
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
public void testSkip() throws IOException {
|
||||||
public void testSkip()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
DocumentInputStream stream = new DocumentInputStream(_workbook);
|
||||||
|
|
||||||
assertEquals(_workbook_size, stream.available());
|
assertEquals(_workbook_size, stream.available());
|
||||||
@ -422,17 +365,4 @@ public class TestDocumentInputStream
|
|||||||
stream.skip(2 + ( long ) Integer.MAX_VALUE));
|
stream.skip(2 + ( long ) Integer.MAX_VALUE));
|
||||||
assertEquals(0, stream.available());
|
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 final class AllPOIFSStorageTests {
|
||||||
|
|
||||||
public static Test suite() {
|
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(TestBATBlock.class);
|
||||||
result.addTestSuite(TestBlockAllocationTableReader.class);
|
result.addTestSuite(TestBlockAllocationTableReader.class);
|
||||||
result.addTestSuite(TestBlockAllocationTableWriter.class);
|
result.addTestSuite(TestBlockAllocationTableWriter.class);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,24 +15,20 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.storage;
|
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.TestCase;
|
||||||
|
|
||||||
import junit.framework.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to test DocumentBlock functionality
|
* Class to test DocumentBlock functionality
|
||||||
*
|
*
|
||||||
* @author Marc Johnson
|
* @author Marc Johnson
|
||||||
*/
|
*/
|
||||||
|
public final class TestDocumentBlock extends TestCase {
|
||||||
public class TestDocumentBlock
|
|
||||||
extends TestCase
|
|
||||||
{
|
|
||||||
static final private byte[] _testdata;
|
static final private byte[] _testdata;
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -44,25 +39,10 @@ public class TestDocumentBlock
|
|||||||
_testdata[ j ] = ( byte ) j;
|
_testdata[ j ] = ( byte ) j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor TestDocumentBlock
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
*/
|
|
||||||
|
|
||||||
public TestDocumentBlock(String name)
|
|
||||||
{
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the writing DocumentBlock constructor.
|
* Test the writing DocumentBlock constructor.
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void testConstructor()
|
public void testConstructor()
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@ -88,46 +68,10 @@ public class TestDocumentBlock
|
|||||||
assertEquals(_testdata.length, size);
|
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
|
* Test 'reading' constructor
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void testReadingConstructor()
|
public void testReadingConstructor()
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@ -164,17 +108,4 @@ public class TestDocumentBlock
|
|||||||
assertEquals(( byte ) 0xFF, copy[ j ]);
|
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
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
@ -16,24 +15,23 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.storage;
|
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.TestCase;
|
||||||
|
|
||||||
import junit.framework.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to test SmallDocumentBlock functionality
|
* Class to test SmallDocumentBlock functionality
|
||||||
*
|
*
|
||||||
* @author Marc Johnson
|
* @author Marc Johnson
|
||||||
*/
|
*/
|
||||||
|
public final class TestSmallDocumentBlock extends TestCase {
|
||||||
public class TestSmallDocumentBlock
|
|
||||||
extends TestCase
|
|
||||||
{
|
|
||||||
static final private byte[] _testdata;
|
static final private byte[] _testdata;
|
||||||
static final private int _testdata_size = 2999;
|
static final private int _testdata_size = 2999;
|
||||||
|
|
||||||
@ -45,25 +43,10 @@ public class TestSmallDocumentBlock
|
|||||||
_testdata[ j ] = ( byte ) j;
|
_testdata[ j ] = ( byte ) j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* constructor
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
*/
|
|
||||||
|
|
||||||
public TestSmallDocumentBlock(String name)
|
|
||||||
{
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test conversion from DocumentBlocks
|
* Test conversion from DocumentBlocks
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void testConvert1()
|
public void testConvert1()
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@ -113,12 +96,7 @@ public class TestSmallDocumentBlock
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test conversion from byte array
|
* Test conversion from byte array
|
||||||
*
|
|
||||||
* @exception IOException;
|
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void testConvert2()
|
public void testConvert2()
|
||||||
throws IOException
|
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
|
* test fill
|
||||||
*
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void testFill()
|
public void testFill()
|
||||||
throws IOException
|
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 final class AllPOIUtilTests {
|
||||||
|
|
||||||
public static Test suite() {
|
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(TestArrayUtil.class);
|
||||||
result.addTestSuite(TestBinaryTree.class);
|
result.addTestSuite(TestBinaryTree.class);
|
||||||
result.addTestSuite(TestBitField.class);
|
result.addTestSuite(TestBitField.class);
|
||||||
result.addTestSuite(TestByteField.class);
|
result.addTestSuite(TestByteField.class);
|
||||||
result.addTestSuite(TestDoubleList2d.class);
|
|
||||||
result.addTestSuite(TestHexDump.class);
|
result.addTestSuite(TestHexDump.class);
|
||||||
result.addTestSuite(TestIntegerField.class);
|
result.addTestSuite(TestIntegerField.class);
|
||||||
result.addTestSuite(TestIntList.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
|
* test the getDouble() method
|
||||||
*/
|
*/
|
||||||
public void testGetDouble() {
|
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);
|
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];
|
byte[] data = new byte[8];
|
||||||
LittleEndian.putDouble(data, nan);
|
LittleEndian.putDouble(data, 0, nan);
|
||||||
for ( int i = 0; i < data.length; i++ ) {
|
for ( int i = 0; i < data.length; i++ ) {
|
||||||
assertEquals(data[i], _nan_double_array[i]);
|
assertEquals(data[i], _nan_double_array[i]);
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ public final class TestLittleEndian extends TestCase {
|
|||||||
(byte) 0x02,
|
(byte) 0x02,
|
||||||
};
|
};
|
||||||
|
|
||||||
assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata));
|
assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata, 0));
|
||||||
assertEquals(0x02FFFFFFFFFFFFFFL, LittleEndian.getLong(testdata, 1));
|
assertEquals(0x02FFFFFFFFFFFFFFL, LittleEndian.getLong(testdata, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ public final class TestLittleEndian extends TestCase {
|
|||||||
public void testPutDouble() {
|
public void testPutDouble() {
|
||||||
byte[] received = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
|
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));
|
assertTrue(compareByteArrays(received, _double_array, 0, LittleEndian.DOUBLE_SIZE));
|
||||||
LittleEndian.putDouble(received, 1, _doubles[1]);
|
LittleEndian.putDouble(received, 1, _doubles[1]);
|
||||||
byte[] expected = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
|
byte[] expected = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
|
||||||
@ -224,7 +224,7 @@ public final class TestLittleEndian extends TestCase {
|
|||||||
|
|
||||||
long testdata0 = 0xFFFFFFFFFFFFFF01L;
|
long testdata0 = 0xFFFFFFFFFFFFFF01L;
|
||||||
long testdata1 = 0x02FFFFFFFFFFFFFFL;
|
long testdata1 = 0x02FFFFFFFFFFFFFFL;
|
||||||
LittleEndian.putLong(received, testdata0);
|
LittleEndian.putLong(received, 0, testdata0);
|
||||||
assertTrue(compareByteArrays(received, expected, 0, LittleEndian.LONG_SIZE));
|
assertTrue(compareByteArrays(received, expected, 0, LittleEndian.LONG_SIZE));
|
||||||
LittleEndian.putLong(received, 1, testdata1);
|
LittleEndian.putLong(received, 1, testdata1);
|
||||||
assertTrue(compareByteArrays(received, expected, 1, LittleEndian.LONG_SIZE));
|
assertTrue(compareByteArrays(received, expected, 1, LittleEndian.LONG_SIZE));
|
||||||
|
@ -42,43 +42,7 @@ public class TestStringUtil
|
|||||||
super( name );
|
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
|
* test getFromUnicodeHigh for symbols with code below and more 127
|
||||||
@ -101,62 +65,7 @@ public class TestStringUtil
|
|||||||
StringUtil.getFromUnicodeLE( test_data ) );
|
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
|
* Test putCompressedUnicode
|
||||||
|
Loading…
Reference in New Issue
Block a user