2002-01-30 21:22:28 -05:00
|
|
|
/* ====================================================================
|
2006-12-22 14:18:16 -05:00
|
|
|
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
|
2004-04-09 09:05:39 -04:00
|
|
|
|
|
|
|
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.
|
|
|
|
==================================================================== */
|
2002-01-30 21:22:28 -05:00
|
|
|
|
|
|
|
package org.apache.poi.hssf.record;
|
|
|
|
|
2008-11-05 20:12:41 -05:00
|
|
|
import java.util.Iterator;
|
|
|
|
|
2010-01-18 07:18:00 -05:00
|
|
|
import org.apache.poi.hssf.record.common.UnicodeString;
|
2008-11-05 20:12:41 -05:00
|
|
|
import org.apache.poi.hssf.record.cont.ContinuableRecord;
|
|
|
|
import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
|
2005-08-18 03:06:44 -04:00
|
|
|
import org.apache.poi.util.IntMapper;
|
2002-01-30 21:22:28 -05:00
|
|
|
import org.apache.poi.util.LittleEndianConsts;
|
|
|
|
|
|
|
|
/**
|
2008-11-05 20:12:41 -05:00
|
|
|
* Title: Static String Table Record (0x00FC)<p/>
|
|
|
|
*
|
2002-01-30 21:22:28 -05:00
|
|
|
* Description: This holds all the strings for LabelSSTRecords.
|
|
|
|
* <P>
|
|
|
|
* REFERENCE: PG 389 Microsoft Excel 97 Developer's Kit (ISBN:
|
|
|
|
* 1-57231-498-2)
|
|
|
|
* <P>
|
|
|
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
|
|
|
* @author Marc Johnson (mjohnson at apache dot org)
|
2002-06-02 03:30:40 -04:00
|
|
|
* @author Glen Stampoultzis (glens at apache.org)
|
2003-06-26 09:33:47 -04:00
|
|
|
*
|
2002-01-30 21:22:28 -05:00
|
|
|
* @see org.apache.poi.hssf.record.LabelSSTRecord
|
|
|
|
* @see org.apache.poi.hssf.record.ContinueRecord
|
|
|
|
*/
|
2008-11-05 20:12:41 -05:00
|
|
|
public final class SSTRecord extends ContinuableRecord {
|
2008-10-30 21:02:55 -04:00
|
|
|
public static final short sid = 0x00FC;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2008-11-05 20:12:41 -05:00
|
|
|
private static final UnicodeString EMPTY_STRING = new UnicodeString("");
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2008-11-05 20:12:41 -05:00
|
|
|
// TODO - move these constants to test class (the only consumer)
|
2002-06-02 03:30:40 -04:00
|
|
|
/** standard record overhead: two shorts (record id plus data space size)*/
|
2008-11-05 20:12:41 -05:00
|
|
|
static final int STD_RECORD_OVERHEAD = 2 * LittleEndianConsts.SHORT_SIZE;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2002-06-02 03:30:40 -04:00
|
|
|
/** SST overhead: the standard record overhead, plus the number of strings and the number of unique strings -- two ints */
|
2008-11-05 20:12:41 -05:00
|
|
|
static final int SST_RECORD_OVERHEAD = STD_RECORD_OVERHEAD + 2 * LittleEndianConsts.INT_SIZE;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2002-06-02 03:30:40 -04:00
|
|
|
/** how much data can we stuff into an SST record? That would be _max minus the standard SST record overhead */
|
2008-11-05 20:12:41 -05:00
|
|
|
static final int MAX_DATA_SPACE = RecordInputStream.MAX_RECORD_DATA_SIZE - 8;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2002-06-02 03:30:40 -04:00
|
|
|
/** union of strings in the SST and EXTSST */
|
|
|
|
private int field_1_num_strings;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2002-06-02 03:30:40 -04:00
|
|
|
/** according to docs ONLY SST */
|
|
|
|
private int field_2_num_unique_strings;
|
2005-08-18 03:06:44 -04:00
|
|
|
private IntMapper field_3_strings;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2002-06-02 03:30:40 -04:00
|
|
|
private SSTDeserializer deserializer;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2003-06-26 09:33:47 -04:00
|
|
|
/** Offsets from the beginning of the SST record (even across continuations) */
|
|
|
|
int[] bucketAbsoluteOffsets;
|
|
|
|
/** Offsets relative the start of the current SST or continue record */
|
|
|
|
int[] bucketRelativeOffsets;
|
|
|
|
|
2002-01-30 21:22:28 -05:00
|
|
|
public SSTRecord()
|
|
|
|
{
|
2002-06-02 03:30:40 -04:00
|
|
|
field_1_num_strings = 0;
|
2002-01-30 21:22:28 -05:00
|
|
|
field_2_num_unique_strings = 0;
|
2005-08-18 03:06:44 -04:00
|
|
|
field_3_strings = new IntMapper();
|
2002-06-02 03:30:40 -04:00
|
|
|
deserializer = new SSTDeserializer(field_3_strings);
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-08-18 03:06:44 -04:00
|
|
|
* Add a string.
|
2002-01-30 21:22:28 -05:00
|
|
|
*
|
|
|
|
* @param string string to be added
|
|
|
|
*
|
|
|
|
* @return the index of that string in the table
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public int addString(UnicodeString string)
|
2002-01-30 21:22:28 -05:00
|
|
|
{
|
|
|
|
field_1_num_strings++;
|
2005-08-18 03:06:44 -04:00
|
|
|
UnicodeString ucs = ( string == null ) ? EMPTY_STRING
|
2002-06-02 03:30:40 -04:00
|
|
|
: string;
|
2003-06-26 09:33:47 -04:00
|
|
|
int rval;
|
2005-08-18 03:06:44 -04:00
|
|
|
int index = field_3_strings.getIndex(ucs);
|
2002-06-02 03:30:40 -04:00
|
|
|
|
2009-08-18 01:29:53 -04:00
|
|
|
if ( index != -1 ) {
|
2005-08-18 03:06:44 -04:00
|
|
|
rval = index;
|
2009-08-18 01:29:53 -04:00
|
|
|
} else {
|
2002-01-30 21:22:28 -05:00
|
|
|
// This is a new string -- we didn't see it among the
|
|
|
|
// strings we've already collected
|
|
|
|
rval = field_3_strings.size();
|
|
|
|
field_2_num_unique_strings++;
|
2005-08-18 03:06:44 -04:00
|
|
|
SSTDeserializer.addToStringTable( field_3_strings, ucs );
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return number of strings
|
|
|
|
*/
|
|
|
|
public int getNumStrings()
|
|
|
|
{
|
|
|
|
return field_1_num_strings;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return number of unique strings
|
|
|
|
*/
|
|
|
|
public int getNumUniqueStrings()
|
|
|
|
{
|
|
|
|
return field_2_num_unique_strings;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a particular string by its index
|
|
|
|
*
|
|
|
|
* @param id index into the array of strings
|
|
|
|
*
|
|
|
|
* @return the desired string
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public UnicodeString getString(int id )
|
2002-01-30 21:22:28 -05:00
|
|
|
{
|
2005-08-18 03:06:44 -04:00
|
|
|
return (UnicodeString) field_3_strings.get( id );
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a debugging string representation
|
|
|
|
*
|
|
|
|
* @return string representation
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public String toString() {
|
2002-01-30 21:22:28 -05:00
|
|
|
StringBuffer buffer = new StringBuffer();
|
|
|
|
|
2002-06-02 03:30:40 -04:00
|
|
|
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++ )
|
2002-01-30 21:22:28 -05:00
|
|
|
{
|
2005-08-18 03:06:44 -04:00
|
|
|
UnicodeString s = (UnicodeString)field_3_strings.get( k );
|
2002-06-02 03:30:40 -04:00
|
|
|
buffer.append( " .string_" + k + " = " )
|
2005-08-18 03:06:44 -04:00
|
|
|
.append( s.getDebugInfo() ).append( "\n" );
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
2002-06-02 03:30:40 -04:00
|
|
|
buffer.append( "[/SST]\n" );
|
2002-01-30 21:22:28 -05:00
|
|
|
return buffer.toString();
|
|
|
|
}
|
|
|
|
|
2009-08-18 01:29:53 -04:00
|
|
|
public short getSid() {
|
2002-01-30 21:22:28 -05:00
|
|
|
return sid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fill the fields from the data
|
|
|
|
* <P>
|
|
|
|
* The data consists of sets of string data. This string data is
|
|
|
|
* arranged as follows:
|
|
|
|
* <P>
|
2003-06-26 09:33:47 -04:00
|
|
|
* <CODE><pre>
|
2002-01-30 21:22:28 -05:00
|
|
|
* 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)
|
2003-06-26 09:33:47 -04:00
|
|
|
* </pre></CODE>
|
2002-01-30 21:22:28 -05:00
|
|
|
* <P>
|
|
|
|
* The string_flag is bit mapped as follows:
|
|
|
|
* <P>
|
|
|
|
* <TABLE>
|
|
|
|
* <TR>
|
|
|
|
* <TH>Bit number</TH>
|
|
|
|
* <TH>Meaning if 0</TH>
|
|
|
|
* <TH>Meaning if 1</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>0</TD>
|
|
|
|
* <TD>string_data is byte[]</TD>
|
|
|
|
* <TD>string_data is short[]</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>1</TD>
|
|
|
|
* <TD>Should always be 0</TD>
|
|
|
|
* <TD>string_flag is defective</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>2</TD>
|
|
|
|
* <TD>extension is not included</TD>
|
|
|
|
* <TD>extension is included</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>3</TD>
|
|
|
|
* <TD>formatting run data is not included</TD>
|
|
|
|
* <TD>formatting run data is included</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>4</TD>
|
|
|
|
* <TD>Should always be 0</TD>
|
|
|
|
* <TD>string_flag is defective</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>5</TD>
|
|
|
|
* <TD>Should always be 0</TD>
|
|
|
|
* <TD>string_flag is defective</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>6</TD>
|
|
|
|
* <TD>Should always be 0</TD>
|
|
|
|
* <TD>string_flag is defective</TH>
|
|
|
|
* <TR>
|
|
|
|
* <TR>
|
|
|
|
* <TD>7</TD>
|
|
|
|
* <TD>Should always be 0</TD>
|
|
|
|
* <TD>string_flag is defective</TH>
|
|
|
|
* <TR>
|
|
|
|
* </TABLE>
|
|
|
|
* <P>
|
|
|
|
* 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
|
|
|
|
*
|
2007-06-29 11:01:01 -04:00
|
|
|
* @param in the RecordInputstream to read the record from
|
2002-01-30 21:22:28 -05:00
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public SSTRecord(RecordInputStream in) {
|
2002-01-30 21:22:28 -05:00
|
|
|
// this method is ALWAYS called after construction -- using
|
|
|
|
// the nontrivial constructor, of course -- so this is where
|
|
|
|
// we initialize our fields
|
2005-08-18 03:06:44 -04:00
|
|
|
field_1_num_strings = in.readInt();
|
|
|
|
field_2_num_unique_strings = in.readInt();
|
|
|
|
field_3_strings = new IntMapper();
|
2002-06-02 03:30:40 -04:00
|
|
|
deserializer = new SSTDeserializer(field_3_strings);
|
2005-08-18 03:06:44 -04:00
|
|
|
deserializer.manufactureStrings( field_2_num_unique_strings, in );
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return an iterator of the strings we hold. All instances are
|
|
|
|
* UnicodeStrings
|
|
|
|
*/
|
|
|
|
Iterator getStrings()
|
|
|
|
{
|
2005-08-18 03:06:44 -04:00
|
|
|
return field_3_strings.iterator();
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return count of the strings we hold.
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
int countStrings() {
|
2002-01-30 21:22:28 -05:00
|
|
|
return field_3_strings.size();
|
|
|
|
}
|
|
|
|
|
2008-11-05 20:12:41 -05:00
|
|
|
protected void serialize(ContinuableRecordOutput out) {
|
|
|
|
SSTSerializer serializer = new SSTSerializer(field_3_strings, getNumStrings(), getNumUniqueStrings() );
|
|
|
|
serializer.serialize(out);
|
2003-06-26 09:33:47 -04:00
|
|
|
bucketAbsoluteOffsets = serializer.getBucketAbsoluteOffsets();
|
|
|
|
bucketRelativeOffsets = serializer.getBucketRelativeOffsets();
|
2002-06-02 03:30:40 -04:00
|
|
|
}
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2009-08-18 01:29:53 -04:00
|
|
|
SSTDeserializer getDeserializer() {
|
2002-06-02 03:30:40 -04:00
|
|
|
return deserializer;
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
2003-06-26 09:33:47 -04:00
|
|
|
/**
|
|
|
|
* Creates an extended string record based on the current contents of
|
|
|
|
* the current SST record. The offset within the stream to the SST record
|
|
|
|
* is required because the extended string record points directly to the
|
|
|
|
* strings in the SST record.
|
|
|
|
* <p>
|
|
|
|
* NOTE: THIS FUNCTION MUST ONLY BE CALLED AFTER THE SST RECORD HAS BEEN
|
|
|
|
* SERIALIZED.
|
|
|
|
*
|
|
|
|
* @param sstOffset The offset in the stream to the start of the
|
|
|
|
* SST record.
|
|
|
|
* @return The new SST record.
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public ExtSSTRecord createExtSSTRecord(int sstOffset) {
|
2003-06-26 09:33:47 -04:00
|
|
|
if (bucketAbsoluteOffsets == null || bucketAbsoluteOffsets == null)
|
|
|
|
throw new IllegalStateException("SST record has not yet been serialized.");
|
|
|
|
|
|
|
|
ExtSSTRecord extSST = new ExtSSTRecord();
|
|
|
|
extSST.setNumStringsPerBucket((short)8);
|
2009-08-18 01:29:53 -04:00
|
|
|
int[] absoluteOffsets = bucketAbsoluteOffsets.clone();
|
|
|
|
int[] relativeOffsets = bucketRelativeOffsets.clone();
|
2003-06-26 09:33:47 -04:00
|
|
|
for ( int i = 0; i < absoluteOffsets.length; i++ )
|
|
|
|
absoluteOffsets[i] += sstOffset;
|
|
|
|
extSST.setBucketOffsets(absoluteOffsets, relativeOffsets);
|
|
|
|
return extSST;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculates the size in bytes of the EXTSST record as it would be if the
|
|
|
|
* record was serialized.
|
|
|
|
*
|
|
|
|
* @return The size of the ExtSST record in bytes.
|
|
|
|
*/
|
2009-08-18 01:29:53 -04:00
|
|
|
public int calcExtSSTRecordSize() {
|
2003-09-25 03:18:08 -04:00
|
|
|
return ExtSSTRecord.getRecordSizeForStrings(field_3_strings.size());
|
2003-06-26 09:33:47 -04:00
|
|
|
}
|
2002-06-02 03:30:40 -04:00
|
|
|
}
|