| Method from org.apache.cocoon.poi.hssf.record.SSTRecord Detail: |
public int addString(String string) {
int rval;
if (string == null)
{
rval = addString("", false);
}
else
{
// scan for characters greater than 255 ... if any are
// present, we have to use 16-bit encoding. Otherwise, we
// can use 8-bit encoding
boolean useUTF16 = false;
char[] data = string.toCharArray();
for (int j = 0; j < data.length; j++)
{
if (data[ j ] > 255)
{
useUTF16 = true;
break;
}
}
rval = addString(string, useUTF16);
}
return rval;
}
Add a string. Determines whether 8-bit encoding can be used, or
whether 16-bit encoding must be used.
THIS IS THE PREFERRED METHOD OF ADDING A STRING. IF YOU USE THE
OTHER ,code>addString METHOD AND FORCE 8-BIT ENCODING ON
A STRING THAT SHOULD USE 16-BIT ENCODING, YOU WILL CORRUPT THE
STRING; IF YOU USE THAT METHOD AND FORCE 16-BIT ENCODING, YOU
ARE WASTING SPACE WHEN THE WORKBOOK IS WRITTEN OUT. |
public int addString(String string,
boolean useUTF16) {
field_1_num_strings++;
String str = (string == null) ? ""
: string;
int rval = -1;
for (int k = 0; k < field_3_strings.size(); k++)
{
if ((( UnicodeString ) field_3_strings.get(k)).getString()
.equals(str))
{
rval = k;
break;
}
}
if (rval == -1)
{
// This is a new string -- we didn't see it among the
// strings we've already collected
UnicodeString ucs = new UnicodeString();
ucs.setString(str);
ucs.setCharCount(( short ) str.length());
ucs.setOptionFlags(( byte ) (useUTF16 ? 1
: 0));
rval = field_3_strings.size();
field_2_num_unique_strings++;
field_3_strings.add(ucs);
}
return rval;
}
Add a string and assert the encoding (8-bit or 16-bit) to be
used.
USE THIS METHOD AT YOUR OWN RISK. IF YOU FORCE 8-BIT ENCODING,
YOU MAY CORRUPT YOUR STRING. IF YOU FORCE 16-BIT ENCODING AND
IT ISN'T NECESSARY, YOU WILL WASTE SPACE WHEN THIS RECORD IS
WRITTEN OUT. |
public byte[] constructBigStringArray() {
byte[][] strings = getUnicodeStrings();
byte[] bigstringarray = new byte[ calculateUCArrayLength(strings) ];
int pos = 0;
for (int k = 0; k < strings.length; k++)
{
System.arraycopy(strings[ k ], 0, bigstringarray, pos,
strings[ k ].length);
pos += strings[ k ].length;
}
return bigstringarray;
}
Construct a byte array consisting of all of the strings in this
record |
int countStrings() {
return field_3_strings.size();
}
|
public boolean equals(Object o) {
if ((o == null) || (o.getClass() != this.getClass()))
{
return false;
}
SSTRecord other = ( SSTRecord ) o;
return ((field_1_num_strings == other
.field_1_num_strings) && (field_2_num_unique_strings == other
.field_2_num_unique_strings) && field_3_strings
.equals(other.field_3_strings));
}
|
protected void fillFields(byte[] data,
short size,
int offset) {
// this method is ALWAYS called after construction -- using
// the nontrivial constructor, of course -- so this is where
// we initialize our fields
field_1_num_strings = LittleEndian.getInt(data, 0 + offset);
field_2_num_unique_strings = LittleEndian.getInt(data, 4 + offset);
field_3_strings = new ArrayList();
setExpected(0);
_unfinished_string = "";
_total_length = 0;
_string_data_offset = 0;
_wide_char = false;
manufactureStrings(data, 8 + offset, size);
}
Fill the fields from the data
The data consists of sets of string data. This string data is
arranged as follows:
short string_length; // length of string data
byte string_flag; // flag specifying special string
// handling
short run_count; // optional count of formatting runs
int extend_length; // optional extension length
char[] string_data; // string data, can be byte[] or
// short[] (length of array is
// string_length)
int[] formatting_runs; // optional formatting runs (length of
// array is run_count)
byte[] extension; // optional extension (length of array
// is extend_length)
The string_flag is bit mapped as follows:
| Bit number |
Meaning if 0 |
Meaning if 1 |
| 0 |
string_data is byte[] |
string_data is short[]
|
| 1 |
Should always be 0 |
string_flag is defective
|
| 2 |
extension is not included |
extension is included
|
| 3 |
formatting run data is not included |
formatting run data is included
|
| 4 |
Should always be 0 |
string_flag is defective
|
| 5 |
Should always be 0 |
string_flag is defective
|
| 6 |
Should always be 0 |
string_flag is defective
|
| 7 |
Should always be 0 |
string_flag is defective
|
We can handle eating the overhead associated with bits 2 or 3
(or both) being set, but we have no idea what to do with the
associated data. The UnicodeString class can handle the byte[]
vs short[] nature of the actual string data |
int getExpected() {
return __expected;
}
|
public int getNumStrings() {
return field_1_num_strings;
}
|
public int getNumUniqueStrings() {
return field_2_num_unique_strings;
}
|
public void getNumUniqueStrings(int count) {
field_2_num_unique_strings = count;
}
USE THIS METHOD AT YOUR OWN PERIL: THE addString
METHODS MANIPULATE THE NUMBER OF UNIQUE STRINGS AS A SIDE
EFFECT; YOUR ATTEMPTS AT MANIPULATING THE UNIQUE STRING COUNT
IS LIKELY TO BE VERY WRONG AND WILL RESULT IN BAD BEHAVIOR WHEN
THIS RECORD IS WRITTEN OUT AND ANOTHER PROCESS ATTEMPTS TO READ
THE RECORD |
public short getSid() {
return sid;
}
|
public String getString(int id) {
return (( UnicodeString ) field_3_strings.get(id)).getString();
}
Get a particular string by its index |
int getStringDataOffset() {
return _string_data_offset;
}
|
Iterator getStrings() {
return field_3_strings.iterator();
}
|
int getTotalLength() {
return _total_length;
}
|
String getUnfinishedString() {
return _unfinished_string;
}
|
public int hashCode() {
return field_2_num_unique_strings;
}
|
boolean isWideChar() {
return _wide_char;
}
|
public void processContinueRecord(byte[] record) {
boolean clean_break;
if (getExpected() == 0)
{
setExpected(LittleEndian.getShort(record));
getStringParameters(record, 0, getExpected());
clean_break = true;
}
else
{
getStringParameters(record, -LittleEndianConsts.SHORT_SIZE,
getExpected());
clean_break = false;
}
byte[] str_data = new byte[ _total_length ];
int length = _string_minimal_overhead
+ (calculateByteCount(getExpected()));
byte[] bstring = new byte[ length ];
// Copy data from the record into the string buffer. Copy
// skips the length of a short in the string buffer, to leave
// room for the string length.
if (clean_break)
{
System.arraycopy(record, LittleEndianConsts.SHORT_SIZE, str_data,
LittleEndianConsts.SHORT_SIZE,
str_data.length - LittleEndianConsts.SHORT_SIZE);
}
else
{
System.arraycopy(record, 0, str_data,
LittleEndianConsts.SHORT_SIZE,
str_data.length - LittleEndianConsts.SHORT_SIZE);
}
// write the string length
LittleEndian.putShort(bstring, 0, ( short ) getExpected());
// write the options flag
bstring[ LittleEndianConsts.SHORT_SIZE ] =
str_data[ LittleEndianConsts.SHORT_SIZE ];
// copy the bytes/words making up the string; skipping past
// all the overhead of the str_data array
System.arraycopy(str_data, _string_data_offset, bstring,
_string_minimal_overhead,
bstring.length - _string_minimal_overhead);
// use special constructor to create the final string
UnicodeString string = new UnicodeString(UnicodeString.sid,
( short ) bstring.length,
bstring, _unfinished_string);
field_3_strings.add(string);
manufactureStrings(record, clean_break ? _total_length
: _total_length
- LittleEndianConsts
.SHORT_SIZE, ( short ) record
.length);
}
Process a Continue record. A Continue record for an SST record
contains the same kind of data that the SST record contains,
with the following exceptions:
- The string counts at the beginning of the SST record are
not in the Continue record
- The first string in the Continue record might NOT begin
with a size. If the last string in the previous record is
continued in this record, the size is determined by that
last string in the previous record; the first string will
begin with a flag byte, followed by the remaining bytes (or
words) of the last string from the previous
record. Otherwise, the first string in the record will
begin with a string length
|
public byte[] serialize() {
byte[] retval = null;
// get the unicode strings as a 2d array
byte[][] strings = getUnicodeStrings();
// get the linear size of that array
int unicodesize = calculateUCArrayLength(strings);
if (unicodesize > _max_data_space)
{
byte[] stringreminant = null;
List records = new ArrayList();
int unipos = 0;
boolean lastneedcontinue = false;
int stringbyteswritten = 0;
boolean finished = false;
boolean first_record = true;
int totalWritten = 0;
while (!finished)
{
byte[] record = null;
int pos = 0;
if (first_record)
{
// writing SST record
record = new byte[ _max ];
pos = writeSSTHeader(record, pos,
_max
- _std_record_overhead);
first_record = false;
}
else
{
// writing continue record
pos = 0;
int to_be_written = (unicodesize - stringbyteswritten)
+ (lastneedcontinue ? 1
: 0);
int size = Math.min(_max - _std_record_overhead,
to_be_written);
if (size == to_be_written)
{
finished = true;
}
record = new byte[ size + _std_record_overhead ];
pos = writeContinueHeader(record, pos, size);
}
if (lastneedcontinue)
{
// write reminant
System.arraycopy(stringreminant, 0, record, pos,
stringreminant.length);
stringbyteswritten += stringreminant.length - 1;
pos += stringreminant.length;
lastneedcontinue = false;
}
for (; unipos < strings.length; unipos++)
{
int available = _max - pos;
if (strings[ unipos ].length < available)
{
System.arraycopy(strings[ unipos ], 0, record, pos,
strings[ unipos ].length);
stringbyteswritten += strings[ unipos ].length;
pos += strings[ unipos ].length;
}
else
{
if (available >= _string_minimal_overhead)
{
System.arraycopy(strings[ unipos ], 0, record,
pos, available);
stringbyteswritten += available;
stringreminant =
new byte[ (strings[ unipos ].length - available) + LittleEndianConsts.BYTE_SIZE ];
System.arraycopy(strings[ unipos ], available,
stringreminant,
LittleEndianConsts.BYTE_SIZE,
strings[ unipos ].length
- available);
stringreminant[ 0 ] =
strings[ unipos ][ LittleEndianConsts.SHORT_SIZE ];
lastneedcontinue = true;
unipos++;
}
else
{
byte[] shortrecord =
new byte[ record.length - available ];
System.arraycopy(record, 0, shortrecord, 0,
LittleEndianConsts.SHORT_SIZE);
LittleEndian.putShort(
shortrecord, LittleEndianConsts.SHORT_SIZE,
( short ) (LittleEndian.getShort(record, LittleEndianConsts.SHORT_SIZE)
- available));
System.arraycopy(record, _std_record_overhead,
shortrecord,
_std_record_overhead,
shortrecord.length
- _std_record_overhead);
record = shortrecord;
}
break;
}
}
records.add(record);
totalWritten += record.length;
}
retval = new byte[ totalWritten ];
int rpos = 0;
Iterator iter = records.iterator();
while (iter.hasNext())
{
byte[] record = ( byte [] ) iter.next();
System.arraycopy(record, 0, retval, rpos, record.length);
rpos += record.length;
}
}
else
{
// short data: write one simple SST record
retval = new byte[ _sst_record_overhead + unicodesize ];
writeSSTHeader(retval, 0, retval.length - _std_record_overhead);
int pos = _sst_record_overhead;
for (int k = 0; k < strings.length; k++)
{
System.arraycopy(strings[ k ], 0, retval, pos,
strings[ k ].length);
pos += strings[ k ].length;
}
}
return retval;
}
Create a byte array consisting of an SST record and any
required Continue records, ready to be written out.
If an SST record and any subsequent Continue records are read
in to create this instance, this method should produce a byte
array that is identical to the byte array produced by
concatenating the input records' data. |
public void setNumStrings(int count) {
field_1_num_strings = count;
}
USE THIS METHOD AT YOUR OWN PERIL: THE addString
METHODS MANIPULATE THE NUMBER OF STRINGS AS A SIDE EFFECT; YOUR
ATTEMPTS AT MANIPULATING THE STRING COUNT IS LIKELY TO BE VERY
WRONG AND WILL RESULT IN BAD BEHAVIOR WHEN THIS RECORD IS
WRITTEN OUT AND ANOTHER PROCESS ATTEMPTS TO READ THE RECORD |
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[SST]\n");
buffer.append(" .numstrings = ")
.append(Integer.toHexString(getNumStrings())).append("\n");
buffer.append(" .uniquestrings = ")
.append(Integer.toHexString(getNumUniqueStrings())).append("\n");
for (int k = 0; k < field_3_strings.size(); k++)
{
buffer.append(" .string_" + k + " = ")
.append((( UnicodeString ) field_3_strings.get(k)).toString())
.append("\n");
}
buffer.append("[/SST]\n");
return buffer.toString();
}
Return a debugging string representation |
protected void validateSid(short id) throws RecordFormatException {
if (id != sid)
{
throw new RecordFormatException("NOT An SST RECORD");
}
}
|