FileDocCategorySizeDatePackage
RecordInputStream.javaAPI DocApache Poi 3.0.19658Mon Jan 01 12:39:40 GMT 2007org.apache.poi.hssf.record

RecordInputStream

public class RecordInputStream extends InputStream
Title: Record Input Stream

Description: Wraps a stream and provides helper methods for the construction of records.

author
Jason Height (jheight @ apache dot org)

Fields Summary
public static final short
MAX_RECORD_DATA_SIZE
Maximum size of a single record (minus the 4 byte header) without a continue
private InputStream
in
protected short
currentSid
protected short
currentLength
protected short
nextSid
protected byte[]
data
protected short
recordOffset
protected long
pos
private boolean
autoContinue
byte[]
NAN_data
Constructors Summary
public RecordInputStream(InputStream in)


        
    this.in = in;
    try {
      nextSid = LittleEndian.readShort(in);
      //Dont increment the pos just yet (technically we are at the start of
      //the record stream until nextRecord is called).      
    } catch (IOException ex) {
      throw new RecordFormatException("Error reading bytes", ex);
    }
  
Methods Summary
protected voidcheckRecordPosition()

    if (remaining() <= 0) {
      if (isContinueNext() && autoContinue) {
        nextRecord();
      }
      else throw new ArrayIndexOutOfBoundsException();
    }    
  
public booleangetAutoContinue()

    return autoContinue;
  
public shortgetLength()

    return currentLength;
  
public byte[]getNANData()

    if (NAN_data == null)
      throw new RecordFormatException("Do NOT call getNANData without calling readDouble that returns NaN");
    return NAN_data;
  
public longgetPos()

    return pos;
  
public shortgetRecordOffset()

    return recordOffset;
  
public shortgetSid()

    return currentSid;
  
public booleanhasNextRecord()

    return (nextSid != 0);
  
public booleanisContinueNext()
Returns true iif a Continue record is next in the excel stream

return
True when a ContinueRecord is next.

    return (nextSid == ContinueRecord.sid);
  
public voidnextRecord()
Moves to the next record in the stream. Note: The auto continue flag is reset to true

    if ((currentLength != -1) && (currentLength != recordOffset)) {
      System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(currentSid));
    }
    currentSid = nextSid;
    pos += LittleEndian.SHORT_SIZE;
    autoContinue = true;
    try {
      recordOffset = 0;
      currentLength = LittleEndian.readShort(in);     
      if (currentLength > MAX_RECORD_DATA_SIZE)
        throw new RecordFormatException("The content of an excel record cannot exceed "+MAX_RECORD_DATA_SIZE+" bytes");
      pos += LittleEndian.SHORT_SIZE;
      in.read(data, 0, currentLength);

      //Read the Sid of the next record
      nextSid = LittleEndian.readShort(in);
    } catch (IOException ex) {
      throw new RecordFormatException("Error reading bytes", ex);
    }
  
public intread()
This method will read a byte from the current record

    checkRecordPosition();

    byte result = data[recordOffset];
    recordOffset += 1;
    pos += 1;
    return result;    
  
public byte[]readAllContinuedRemainder()
Reads all byte data for the current record, including any that overlaps into any following continue records.

deprecated
Best to write a input stream that wraps this one where there is special sub record that may overlap continue records.

    //Using a ByteArrayOutputStream is just an easy way to get a
    //growable array of the data.
    ByteArrayOutputStream out = new ByteArrayOutputStream(2*MAX_RECORD_DATA_SIZE);

    while (isContinueNext()) {
      byte[] b = readRemainder();      
      out.write(b, 0, b.length);
      nextRecord();
    }
    byte[] b = readRemainder();      
    out.write(b, 0, b.length);    
    
    return out.toByteArray();
  
public bytereadByte()

    checkRecordPosition();
    
    byte result = data[recordOffset];
    recordOffset += 1;
    pos += 1;
    return result;
  
public java.lang.StringreadCompressedUnicode(int length)

    if ((length < 0) || (remaining() < length)) {
            throw new IllegalArgumentException("Illegal length");
    }

    StringBuffer buf = new StringBuffer(length);
    for (int i=0;i<length;i++) {
      if ((remaining() == 0) && (isContinueNext()))
        nextRecord();
      byte b = readByte();
      //Typecast direct to char from byte with high bit set causes all ones
      //in the high byte of the char (which is of course incorrect)
      char ch = (char)( (short)0xff & (short)b );
      buf.append(ch); 
    }
    return buf.toString();    
  
public doublereadDouble()

     
    checkRecordPosition();    
    //Reset NAN data
    NAN_data = null;
    double result = LittleEndian.getDouble(data, recordOffset);
    //Excel represents NAN in several ways, at this point in time we do not often
    //know the sequence of bytes, so as a hack we store the NAN byte sequence
    //so that it is not corrupted.
    if (Double.isNaN(result)) {
      NAN_data = new byte[8];
      System.arraycopy(data, recordOffset, NAN_data, 0, 8);
    }
    
    recordOffset += LittleEndian.DOUBLE_SIZE;
    pos += LittleEndian.DOUBLE_SIZE;
    return result;
  
public intreadInt()

    checkRecordPosition();
    
    int result = LittleEndian.getInt(data, recordOffset);
    recordOffset += LittleEndian.INT_SIZE;
    pos += LittleEndian.INT_SIZE;
    return result;
  
public longreadLong()

    checkRecordPosition();    
    
    long result = LittleEndian.getLong(data, recordOffset);
    recordOffset += LittleEndian.LONG_SIZE;
    pos += LittleEndian.LONG_SIZE;
    return result;
  
public byte[]readRemainder()
Returns the remaining bytes for the current record.

return
The remaining bytes of the current record.

    int size = remaining();
    byte[] result = new byte[size];
    System.arraycopy(data, recordOffset, result, 0, size);
    recordOffset += size;
    pos += size;
    return result;
  
public shortreadShort()

    checkRecordPosition();
    
    short result = LittleEndian.getShort(data, recordOffset);
    recordOffset += LittleEndian.SHORT_SIZE;
    pos += LittleEndian.SHORT_SIZE;
    return result;
  
public short[]readShortArray()

    checkRecordPosition();
    
    short[] arr = LittleEndian.getShortArray(data, recordOffset);
    final int size = (2 * (arr.length +1));
    recordOffset += size;
    pos += size;
    
    return arr;
  
public intreadUShort()

    checkRecordPosition();    
    
    int result = LittleEndian.getUShort(data, recordOffset);
    recordOffset += LittleEndian.SHORT_SIZE;
    pos += LittleEndian.SHORT_SIZE;
    return result;
  
public java.lang.StringreadUnicodeLEString(int length)
given a byte array of 16-bit unicode characters, compress to 8-bit and return a string { 0x16, 0x00 } -0x16

param
len the length of the final string
return
the converted string
exception
IllegalArgumentException if len is too large (i.e., there is not enough data in string to create a String of that length)

    if ((length < 0) || (((remaining() / 2) < length) && !isContinueNext())) {
            throw new IllegalArgumentException("Illegal length");
    }
    
    StringBuffer buf = new StringBuffer(length);
    for (int i=0;i<length;i++) {
      if ((remaining() == 0) && (isContinueNext()))
        nextRecord();
      char ch = (char)readShort();
      buf.append(ch); 
    }
    return buf.toString();
  
public org.apache.poi.hssf.record.UnicodeStringreadUnicodeString()
Returns an excel style unicode string from the bytes reminaing in the record. Note: Unicode strings differ from normal strings due to the addition of formatting information.

return
The unicode string representation of the remaining bytes.

    return new UnicodeString(this);
  
public intremaining()
The remaining number of bytes in the current record.

return
The number of bytes remaining in the current record

    return (currentLength - recordOffset);
  
public voidsetAutoContinue(boolean enable)

    this.autoContinue = enable;