180 lines
6.5 KiB
Java
180 lines
6.5 KiB
Java
package jxl.read.biff;
|
|
|
|
import common.Assert;
|
|
import jxl.WorkbookSettings;
|
|
import jxl.biff.IntegerHelper;
|
|
import jxl.biff.RecordData;
|
|
import jxl.biff.StringHelper;
|
|
|
|
class SSTRecord extends RecordData {
|
|
private int totalStrings;
|
|
|
|
private int uniqueStrings;
|
|
|
|
private String[] strings;
|
|
|
|
private int[] continuationBreaks;
|
|
|
|
private static class ByteArrayHolder {
|
|
public byte[] bytes;
|
|
|
|
private ByteArrayHolder() {}
|
|
}
|
|
|
|
private static class BooleanHolder {
|
|
public boolean value;
|
|
|
|
private BooleanHolder() {}
|
|
}
|
|
|
|
public SSTRecord(Record t, Record[] continuations, WorkbookSettings ws) {
|
|
super(t);
|
|
int totalRecordLength = 0;
|
|
for (int i = 0; i < continuations.length; i++)
|
|
totalRecordLength += continuations[i].getLength();
|
|
totalRecordLength += getRecord().getLength();
|
|
byte[] data = new byte[totalRecordLength];
|
|
int pos = 0;
|
|
System.arraycopy(getRecord().getData(), 0, data, 0, getRecord().getLength());
|
|
pos += getRecord().getLength();
|
|
this.continuationBreaks = new int[continuations.length];
|
|
Record r = null;
|
|
for (int j = 0; j < continuations.length; j++) {
|
|
r = continuations[j];
|
|
System.arraycopy(r.getData(), 0, data, pos, r.getLength());
|
|
this.continuationBreaks[j] = pos;
|
|
pos += r.getLength();
|
|
}
|
|
this.totalStrings = IntegerHelper.getInt(data[0], data[1], data[2], data[3]);
|
|
this.uniqueStrings = IntegerHelper.getInt(data[4], data[5], data[6], data[7]);
|
|
this.strings = new String[this.uniqueStrings];
|
|
readStrings(data, 8, ws);
|
|
}
|
|
|
|
private void readStrings(byte[] data, int offset, WorkbookSettings ws) {
|
|
int pos = offset;
|
|
String s = null;
|
|
boolean asciiEncoding = false;
|
|
boolean richString = false;
|
|
boolean extendedString = false;
|
|
int formattingRuns = 0;
|
|
int extendedRunLength = 0;
|
|
for (int i = 0; i < this.uniqueStrings; i++) {
|
|
int numChars = IntegerHelper.getInt(data[pos], data[pos + 1]);
|
|
pos += 2;
|
|
byte optionFlags = data[pos];
|
|
pos++;
|
|
extendedString = ((optionFlags & 0x4) != 0);
|
|
richString = ((optionFlags & 0x8) != 0);
|
|
if (richString) {
|
|
formattingRuns = IntegerHelper.getInt(data[pos], data[pos + 1]);
|
|
pos += 2;
|
|
}
|
|
if (extendedString) {
|
|
extendedRunLength = IntegerHelper.getInt(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
|
|
pos += 4;
|
|
}
|
|
asciiEncoding = ((optionFlags & 0x1) == 0);
|
|
ByteArrayHolder bah = new ByteArrayHolder();
|
|
BooleanHolder bh = new BooleanHolder();
|
|
bh.value = asciiEncoding;
|
|
pos += getChars(data, bah, pos, bh, numChars);
|
|
asciiEncoding = bh.value;
|
|
if (asciiEncoding) {
|
|
s = StringHelper.getString(bah.bytes, numChars, 0, ws);
|
|
} else {
|
|
s = StringHelper.getUnicodeString(bah.bytes, numChars, 0);
|
|
}
|
|
this.strings[i] = s;
|
|
if (richString)
|
|
pos += 4 * formattingRuns;
|
|
if (extendedString)
|
|
pos += extendedRunLength;
|
|
if (pos > data.length)
|
|
Assert.verify(false, "pos exceeds record length");
|
|
}
|
|
}
|
|
|
|
private int getChars(byte[] source, ByteArrayHolder bah, int pos, BooleanHolder ascii, int numChars) {
|
|
int charsRead, i = 0;
|
|
boolean spansBreak = false;
|
|
if (ascii.value) {
|
|
bah.bytes = new byte[numChars];
|
|
} else {
|
|
bah.bytes = new byte[numChars * 2];
|
|
}
|
|
while (i < this.continuationBreaks.length && !spansBreak) {
|
|
spansBreak = (pos <= this.continuationBreaks[i] && pos + bah.bytes.length > this.continuationBreaks[i]);
|
|
if (!spansBreak)
|
|
i++;
|
|
}
|
|
if (!spansBreak) {
|
|
System.arraycopy(source, pos, bah.bytes, 0, bah.bytes.length);
|
|
return bah.bytes.length;
|
|
}
|
|
int breakpos = this.continuationBreaks[i];
|
|
System.arraycopy(source, pos, bah.bytes, 0, breakpos - pos);
|
|
int bytesRead = breakpos - pos;
|
|
if (ascii.value) {
|
|
charsRead = bytesRead;
|
|
} else {
|
|
charsRead = bytesRead / 2;
|
|
}
|
|
bytesRead += getContinuedString(source, bah, bytesRead, i, ascii, numChars - charsRead);
|
|
return bytesRead;
|
|
}
|
|
|
|
private int getContinuedString(byte[] source, ByteArrayHolder bah, int destPos, int contBreakIndex, BooleanHolder ascii, int charsLeft) {
|
|
int breakpos = this.continuationBreaks[contBreakIndex];
|
|
int bytesRead = 0;
|
|
while (charsLeft > 0) {
|
|
Assert.verify((contBreakIndex < this.continuationBreaks.length), "continuation break index");
|
|
if (ascii.value && source[breakpos] == 0) {
|
|
int length = (contBreakIndex == this.continuationBreaks.length - 1) ? charsLeft : Math.min(charsLeft, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
|
|
System.arraycopy(source, breakpos + 1, bah.bytes, destPos, length);
|
|
destPos += length;
|
|
bytesRead += length + 1;
|
|
charsLeft -= length;
|
|
ascii.value = true;
|
|
} else if (!ascii.value && source[breakpos] != 0) {
|
|
int length = (contBreakIndex == this.continuationBreaks.length - 1) ? (charsLeft * 2) : Math.min(charsLeft * 2, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
|
|
System.arraycopy(source, breakpos + 1, bah.bytes, destPos, length);
|
|
destPos += length;
|
|
bytesRead += length + 1;
|
|
charsLeft -= length / 2;
|
|
ascii.value = false;
|
|
} else if (!ascii.value && source[breakpos] == 0) {
|
|
int chars = (contBreakIndex == this.continuationBreaks.length - 1) ? charsLeft : Math.min(charsLeft, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
|
|
for (int j = 0; j < chars; j++) {
|
|
bah.bytes[destPos] = source[breakpos + j + 1];
|
|
destPos += 2;
|
|
}
|
|
bytesRead += chars + 1;
|
|
charsLeft -= chars;
|
|
ascii.value = false;
|
|
} else {
|
|
byte[] oldBytes = bah.bytes;
|
|
bah.bytes = new byte[destPos * 2 + charsLeft * 2];
|
|
for (int j = 0; j < destPos; j++)
|
|
bah.bytes[j * 2] = oldBytes[j];
|
|
destPos *= 2;
|
|
int length = (contBreakIndex == this.continuationBreaks.length - 1) ? (charsLeft * 2) : Math.min(charsLeft * 2, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
|
|
System.arraycopy(source, breakpos + 1, bah.bytes, destPos, length);
|
|
destPos += length;
|
|
bytesRead += length + 1;
|
|
charsLeft -= length / 2;
|
|
ascii.value = false;
|
|
}
|
|
contBreakIndex++;
|
|
if (contBreakIndex < this.continuationBreaks.length)
|
|
breakpos = this.continuationBreaks[contBreakIndex];
|
|
}
|
|
return bytesRead;
|
|
}
|
|
|
|
public String getString(int index) {
|
|
Assert.verify((index < this.uniqueStrings));
|
|
return this.strings[index];
|
|
}
|
|
}
|