Files
HRMS/hrmsEjb/jxl/read/biff/SSTRecord.java
2025-07-28 13:56:49 +05:30

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];
}
}