This commit was manufactured by cvs2svn to create tag

'REL_1_5_BRANCH_MERGE3'.

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/tags/REL_1_5_BRANCH_MERGE3@352659 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
No Author 2002-06-01 02:25:53 +00:00
parent f32748f389
commit daf9ec6e8b
29 changed files with 1757 additions and 1337 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -39,6 +39,7 @@
<menu label="Get Involved">
<menu-item label="Contributing" href="contrib.html"/>
<menu-item label="Branching" href="branching.html"/>
<menu-item label="Bug Database" href="http://nagoya.apache.org/bugzilla/buglist.cgi?product=POI"/>
<menu-item label="CVS" href="http://jakarta.apache.org/site/cvsindex.html"/>
<menu-item label="Mail Lists" href="http://jakarta.apache.org/site/mail.html"/>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN" "./dtd/document-v11.dtd">
<document>
<header>
<title>Branching</title>
<authors>
<person id="GJS" name="Glen Stampoultzis" email="glens@apache.org"/>
</authors>
</header>
<body>
<section title="Branching Conventions">
<p>
Branches are tagged in the following way:
</p>
<ul>
<li>REL_1_5_BRANCH</li>
<li>REL_2_0_BRANCH</li>
</ul>
<p>
Merge points should be tagged as follows:
</p>
<ul>
<li>REL_1_5_BRANCH_MERGE1</li>
<li>REL_1_5_BRANCH_MERGE2</li>
<li>etc...</li>
</ul>
<p>
Releases should be tagged as:
</p>
<ul>
<li>REL_1_5</li>
<li>REL_1_5_1</li>
<li>REL_1_5_2</li>
<li>etc...</li>
</ul>
</section>
<section title="Branching Advise">
<p>
Don't forget which branch you are currently on. This is critically
important. Committing stuff to the wrong branch causes all sorts of
headaches. Best to name your checkout after the branch you are on.
</p>
</section>
<section title="Who Manages Branching?">
<p>
All branching is currently managed by Glen Stampoultzis. If you wish
to create your own branch please let him know. Merging is also
handled by Glen. Just pop him a mail if you feel it's necessary to
create a branch or perform a merge.
</p>
<p>
The reason to go through a single point for branching is that it can be
an easy thing to get wrong. Having a single person managing branches
means there is less chance of getting getting our wires crossed with this
difficult area of CVS.
</p>
</section>
<section title="Currently Active Branches">
<p>
The following branches are currently active:
</p>
<table>
<tr>
<th>
<b>Branch</b>
</th>
<th>
<b>Description</b>
</th>
</tr>
<tr>
<td>
HEAD
</td>
<td>
This is the trunk and is always active. Currently it is being used to continue development
of the 2.0 release.
</td>
</tr>
<tr>
<td>
REL_1_5_BRANCH
</td>
<td>
All bug fixes not specifically relevant to the 2.0 work should be placed in this branch.
From here they will merged back to the trunk and the merge point marked.
</td>
</tr>
</table>
</section>
</body>
</document>

View File

@ -3,7 +3,7 @@
<document>
<header>
<title></title>
<title>Project History</title>
<authors>
<person id="AO" name="Andrew C. Oliver" email="acoliver@apache.org"/>
</authors>

View File

@ -2,114 +2,139 @@
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN" "document-v11.dtd">
<document>
<header>
<title></title>
<authors>
<person id="AO" name="Andrew C. Oliver" email="acoliver@apache.org"/>
</authors>
</header>
<header>
<title></title>
<authors>
<person id="AO" name="Andrew C. Oliver" email="acoliver@apache.org"/>
<person id="GS" name="Glen Stampoultzis" email="glens@apache.org"/>
</authors>
</header>
<body>
<section title="POI logos">
<p>
Here are the current logo submissions. Thanks to the artists!
</p>
<section title="Michael Mosmann">
<body>
<section title="POI logos">
<p>
Here are the current logo submissions. Thanks to the artists!
</p>
<section title="Michael Mosmann">
<p>
<img src="images/logoMichaelMosmann.png"/>
<img src="images/logoMichaelMosmann.png"/>
</p>
</section>
<section title="Loïc Lefèvre">
</section>
<section title="Loïc Lefèvre">
<p>
<img src="images/logoLoicLefevre.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoLoicLefevre2.png"/>
<img src="images/logoLoicLefevre.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoLoicLefevre2.png"/>
</p>
</section>
<section title="Glen Stampoultzis">
</section>
<section title="Glen Stampoultzis">
<p>
<img src="images/logoGlenStampoutlzis.png"/>
<img src="images/logoGlenStampoutlzis.png"/>
</p>
</section>
<section title="Marcus Gustafsson">
</section>
<section title="Marcus Gustafsson">
<p>
<img src="images/logoGustafsson1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoGustafsson2.png"/>
<img src="images/logoGustafsson1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoGustafsson2.png"/>
</p>
</section>
<section title="Adrianus Handoyo">
</section>
<section title="Adrianus Handoyo">
<p>
<img src="images/logoAdria1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoAdria2.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoAdria3.png"/>
<img src="images/logoAdria1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoAdria2.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoAdria3.png"/>
</p>
</section>
<section title="RussellBeattie">
</section>
<section title="RussellBeattie">
<p>
<img src="images/logoRussellBeattie1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRussellBeattie2.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRussellBeattie3.png"/>
<img src="images/logoRussellBeattie1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRussellBeattie2.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRussellBeattie3.png"/>
</p>
<p>
<img src="images/logoRussellBeattie4.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRussellBeattie5.png"/>
<img src="images/logoRussellBeattie4.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRussellBeattie5.png"/>
</p>
</section>
<section title="Daniel Fernandez">
</section>
<section title="Daniel Fernandez">
<p>
<img src="images/logoDanielFernandez.png"/>
<img src="images/logoDanielFernandez.png"/>
</p>
</section>
<section title="Andrew Clements">
</section>
<section title="Andrew Clements">
<p>
<img src="images/logoAndrewClements.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoAndrewClements2.png"/>
<img src="images/logoAndrewClements.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoAndrewClements2.png"/>
</p>
</section>
<section title="Wendy Wise">
</section>
<section title="Wendy Wise">
<p>
<img src="images/logoWendyWise.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoWendyWise2.png"/>
<img src="images/logoWendyWise.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoWendyWise2.png"/>
</p>
</section>
<section title="Nikhil Karmokar">
</section>
<section title="Nikhil Karmokar">
<p>
<img src="images/logoKarmokar1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar1s.png"/>
<img src="images/logoKarmokar1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar1s.png"/>
</p>
<p>
<img src="images/logoKarmokar2.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar2s.png"/>
<img src="images/logoKarmokar2.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar2s.png"/>
</p>
<p>
<img src="images/logoKarmokar3.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar3s.png"/>
<img src="images/logoKarmokar3.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar3s.png"/>
</p>
<p>
<img src="images/logoKarmokar4.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar4s.png"/>
<img src="images/logoKarmokar4.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar4s.png"/>
</p>
<p>
<img src="images/logoKarmokar5.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar5s.png"/>
<img src="images/logoKarmokar5.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar5s.png"/>
</p>
<p>
<img src="images/logoKarmokar6.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar6s.png"/>
<img src="images/logoKarmokar6.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoKarmokar6s.png"/>
</p>
</section>
<section title="Lieven Janssen">
</section>
<section title="Lieven Janssen">
<p>
<img src="images/logoJanssen1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoJanssen2.png"/>
<img src="images/logoJanssen1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoJanssen2.png"/>
</p>
</section>
</section>
<section title="RaPi GmbH">
<p>
Contact Person: Fancy at: fancy at my-feiqi.com
</p>
<p>
<img src="images/logoRaPiGmbH1.png"/>&nbsp;&nbsp;&nbsp;
<img src="images/logoRaPiGmbH2.png"/>
</p>
<p>
<img src="images/logoRaPiGmbH3.png"/>
</p>
<p>
<img src="images/logoRaPiGmbH4.png"/>
</p>
<p>
<img src="images/logoRaPiGmbH5.png"/>
</p>
<p>
<img src="images/logoRaPiGmbH6.png"/>
</p>
<p>
<img src="images/logoRaPiGmbH7.png"/>
</p>
</section>
</section>
</body>
<footer>
<legal>
Copyright (c) @year@ The Apache Software Foundation All rights reserved.
$Revision$ $Date$
</legal>
</footer>
</section>
</body>
<footer>
<legal>
Copyright (c) @year@ The Apache Software Foundation All rights reserved.
$Revision$ $Date$
</legal>
</footer>
</document>

View File

@ -631,12 +631,12 @@ public class BiffViewer
retval = new LinkedDataRecord(rectype, size, data);
break;
case FormulaRecord.sid:
retval = new FormulaRecord(rectype, size, data);
break;
// case FormulaRecord.sid:
// retval = new FormulaRecord(rectype, size, data);
// break;
case SheetPropertiesRecord.sid:
retval = new FormulaRecord(rectype, size, data);
retval = new SheetPropertiesRecord(rectype, size, data);
break;

View File

@ -643,26 +643,11 @@ public class Workbook
{
log.log(DEBUG, "Serializing Workbook with offsets");
// ArrayList bytes = new ArrayList(records.size());
// int arraysize = getSize(); // 0;
int pos = 0;
// for (int k = 0; k < records.size(); k++)
// {
// bytes.add((( Record ) records.get(k)).serialize());
//
// }
// for (int k = 0; k < bytes.size(); k++)
// {
// arraysize += (( byte [] ) bytes.get(k)).length;
// }
for (int k = 0; k < records.size(); k++)
{
// byte[] rec = (( byte [] ) bytes.get(k));
// System.arraycopy(rec, 0, data, offset + pos, rec.length);
pos += (( Record ) records.get(k)).serialize(pos + offset,
data); // rec.length;
pos += (( Record ) records.get(k)).serialize(pos + offset, data); // rec.length;
}
log.log(DEBUG, "Exiting serialize workbook");
return pos;

View File

@ -161,9 +161,7 @@ public class ContinueRecord
// how many continue records do we need
// System.out.println("In ProcessContinue");
int records =
(data.length
/ 8214); // we've a 1 offset but we're also off by one due to rounding...so it balances out
int records = (data.length / 8214); // we've a 1 offset but we're also off by one due to rounding...so it balances out
int offset = 8214;
// System.out.println("we have "+records+" continue records to process");
@ -174,8 +172,7 @@ public class ContinueRecord
for (int cr = 0; cr < records; cr++)
{
ContinueRecord contrec = new ContinueRecord();
int arraysize = Math.min((8214 - 4),
(data.length - offset));
int arraysize = Math.min((8214 - 4), (data.length - offset));
byte[] crdata = new byte[ arraysize ];
System.arraycopy(data, offset, crdata, 0, arraysize);

View File

@ -0,0 +1,202 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache POI" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache POI", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.poi.hssf.record;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndian;
/**
* Process a single record. That is, an SST record or a continue record.
* Refactored from code originally in SSTRecord.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
class RecordProcessor
{
private byte[] data;
private int recordOffset;
private int available;
private SSTRecordHeader sstRecordHeader;
public RecordProcessor( byte[] data, int available, int numStrings, int numUniqueStrings )
{
this.data = data;
this.available = available;
this.sstRecordHeader = new SSTRecordHeader(numStrings, numUniqueStrings);
}
public int getAvailable()
{
return available;
}
public void writeRecordHeader( int offset, int totalWritten, int recordLength, boolean first_record )
{
if ( first_record )
{
available -= 8;
recordOffset = sstRecordHeader.writeSSTHeader( data, recordOffset + offset + totalWritten, recordLength );
}
else
{
recordOffset = writeContinueHeader( data, recordOffset + offset + totalWritten, recordLength );
}
}
public byte[] writeStringRemainder( boolean lastStringCompleted, byte[] stringreminant, int offset, int totalWritten )
{
if ( !lastStringCompleted )
{
// write reminant -- it'll all fit neatly
System.arraycopy( stringreminant, 0, data, recordOffset + offset + totalWritten, stringreminant.length );
adjustPointers( stringreminant.length );
}
else
{
// write as much of the remnant as possible
System.arraycopy( stringreminant, 0, data, recordOffset + offset + totalWritten, available );
byte[] leftover = new byte[( stringreminant.length - available ) + LittleEndianConsts.BYTE_SIZE];
System.arraycopy( stringreminant, available, leftover, LittleEndianConsts.BYTE_SIZE, stringreminant.length - available );
leftover[0] = stringreminant[0];
stringreminant = leftover;
adjustPointers( available ); // Consume all available remaining space
}
return stringreminant;
}
public void writeWholeString( UnicodeString unistr, int offset, int totalWritten )
{
unistr.serialize( recordOffset + offset + totalWritten, data );
int rsize = unistr.getRecordSize();
adjustPointers( rsize );
}
public byte[] writePartString( UnicodeString unistr, int offset, int totalWritten )
{
byte[] stringReminant;
byte[] ucs = unistr.serialize();
System.arraycopy( ucs, 0, data, recordOffset + offset + totalWritten, available );
stringReminant = new byte[( ucs.length - available ) + LittleEndianConsts.BYTE_SIZE];
System.arraycopy( ucs, available, stringReminant, LittleEndianConsts.BYTE_SIZE, ucs.length - available );
stringReminant[0] = ucs[LittleEndianConsts.SHORT_SIZE];
available = 0;
return stringReminant;
}
private int writeContinueHeader( final byte[] data, final int pos,
final int recsize )
{
int offset = pos;
LittleEndian.putShort( data, offset, ContinueRecord.sid );
offset += LittleEndianConsts.SHORT_SIZE;
LittleEndian.putShort( data, offset, (short) ( recsize ) );
offset += LittleEndianConsts.SHORT_SIZE;
return offset - pos;
}
private void adjustPointers( int amount )
{
recordOffset += amount;
available -= amount;
}
}
class SSTRecordHeader
{
int numStrings;
int numUniqueStrings;
/**
*
*/
public SSTRecordHeader( int numStrings, int numUniqueStrings )
{
this.numStrings = numStrings;
this.numUniqueStrings = numUniqueStrings;
}
/**
* Writes out the SST record. This consists of the sid, the record size, the number of
* strings and the number of unique strings.
*
* @param data The data buffer to write the header to.
* @param bufferIndex The index into the data buffer where the header should be written.
* @param recSize The number of records written.
*
* @return The bufer of bytes modified.
*/
public int writeSSTHeader( byte[] data, int bufferIndex, int recSize )
{
int offset = bufferIndex;
LittleEndian.putShort( data, offset, SSTRecord.sid );
offset += LittleEndianConsts.SHORT_SIZE;
LittleEndian.putShort( data, offset, (short) ( recSize ) );
offset += LittleEndianConsts.SHORT_SIZE;
// LittleEndian.putInt( data, offset, getNumStrings() );
LittleEndian.putInt( data, offset, numStrings );
offset += LittleEndianConsts.INT_SIZE;
// LittleEndian.putInt( data, offset, getNumUniqueStrings() );
LittleEndian.putInt( data, offset, numUniqueStrings );
offset += LittleEndianConsts.INT_SIZE;
return offset - bufferIndex;
}
}

View File

@ -452,8 +452,8 @@ public class RowRecord
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) 16);
LittleEndian.putShort(data, 4 + offset, getRowNumber());
LittleEndian.putShort(data, 6 + offset, getFirstCol());
LittleEndian.putShort(data, 8 + offset, getLastCol());
LittleEndian.putShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol());
LittleEndian.putShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol());
LittleEndian.putShort(data, 10 + offset, getHeight());
LittleEndian.putShort(data, 12 + offset, getOptimize());
LittleEndian.putShort(data, 14 + offset, field_6_reserved);

View File

@ -0,0 +1,357 @@
package org.apache.poi.hssf.record;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.BinaryTree;
import org.apache.poi.util.HexDump;
import java.io.IOException;
class SSTDeserializer
{
private BinaryTree strings;
/** this is the number of characters we expect in the first sub-record in a subsequent continuation record */
private int continuationExpectedChars;
/** this is the string we were working on before hitting the end of the current record. This string is NOT finished. */
private String unfinishedString;
/** this is the total length of the current string being handled */
private int totalLengthBytes;
/** this is the offset into a string field of the actual string data */
private int stringDataOffset;
/** this is true if the string uses wide characters */
private boolean wideChar;
public SSTDeserializer(BinaryTree strings)
{
this.strings = strings;
setExpectedChars( 0 );
unfinishedString = "";
totalLengthBytes = 0;
stringDataOffset = 0;
wideChar = false;
}
/**
* This is the starting point where strings are constructed. Note that
* strings may span across multiple continuations. Read the SST record
* carefully before beginning to hack.
*/
public void manufactureStrings( final byte[] data, final int index,
short size )
{
int offset = index;
while ( offset < size )
{
int remaining = size - offset;
if ( ( remaining > 0 ) && ( remaining < LittleEndianConsts.SHORT_SIZE ) )
{
throw new RecordFormatException( "Cannot get length of the last string in SSTRecord" );
}
if ( remaining == LittleEndianConsts.SHORT_SIZE )
{
setExpectedChars( LittleEndian.getUShort( data, offset ) );
unfinishedString = "";
break;
}
short charCount = LittleEndian.getShort( data, offset );
setupStringParameters( data, offset, charCount );
if ( remaining < totalLengthBytes )
{
setExpectedChars( calculateCharCount( totalLengthBytes - remaining ) );
charCount -= getExpectedChars();
totalLengthBytes = remaining;
}
else
{
setExpectedChars( 0 );
}
processString( data, offset, charCount );
offset += totalLengthBytes;
if ( getExpectedChars() != 0 )
{
break;
}
}
}
/**
* Detemines the option types for the string (ie, compressed or uncompressed unicode, rich text string or
* plain string etc) and calculates the length and offset for the string.
*
* @param data
* @param index
* @param char_count
*/
private void setupStringParameters( final byte[] data, final int index,
final int char_count )
{
byte optionFlag = data[index + LittleEndianConsts.SHORT_SIZE];
wideChar = ( optionFlag & 1 ) == 1;
boolean farEast = ( optionFlag & 4 ) == 4;
boolean richText = ( optionFlag & 8 ) == 8;
totalLengthBytes = SSTRecord.STRING_MINIMAL_OVERHEAD + calculateByteCount( char_count );
stringDataOffset = SSTRecord.STRING_MINIMAL_OVERHEAD;
if ( richText )
{
short run_count = LittleEndian.getShort( data, index + stringDataOffset );
stringDataOffset += LittleEndianConsts.SHORT_SIZE;
totalLengthBytes += LittleEndianConsts.SHORT_SIZE + ( LittleEndianConsts.INT_SIZE * run_count );
}
if ( farEast )
{
int extension_length = LittleEndian.getInt( data, index + stringDataOffset );
stringDataOffset += LittleEndianConsts.INT_SIZE;
totalLengthBytes += LittleEndianConsts.INT_SIZE + extension_length;
}
}
private void processString( final byte[] data, final int index,
final short char_count )
{
byte[] stringDataBuffer = new byte[totalLengthBytes];
int length = SSTRecord.STRING_MINIMAL_OVERHEAD + calculateByteCount( char_count );
byte[] bstring = new byte[length];
System.arraycopy( data, index, stringDataBuffer, 0, stringDataBuffer.length );
int offset = 0;
LittleEndian.putShort( bstring, offset, char_count );
offset += LittleEndianConsts.SHORT_SIZE;
bstring[offset] = stringDataBuffer[offset];
// System.out.println( "offset = " + stringDataOffset );
// System.out.println( "length = " + (bstring.length - STRING_MINIMAL_OVERHEAD) );
// System.out.println( "src.length = " + str_data.length );
// try
// {
// System.out.println( "----------------------- DUMP -------------------------" );
// HexDump.dump( stringDataBuffer, (long)stringDataOffset, System.out, 1);
// }
// catch ( IOException e )
// {
// }
// catch ( ArrayIndexOutOfBoundsException e )
// {
// }
// catch ( IllegalArgumentException e )
// {
// }
System.arraycopy( stringDataBuffer, stringDataOffset, bstring,
SSTRecord.STRING_MINIMAL_OVERHEAD,
bstring.length - SSTRecord.STRING_MINIMAL_OVERHEAD );
UnicodeString string = new UnicodeString( UnicodeString.sid,
(short) bstring.length,
bstring );
if ( getExpectedChars() != 0 )
{
unfinishedString = string.getString();
}
else
{
Integer integer = new Integer( strings.size() );
addToStringTable( strings, integer, string );
}
}
/**
* Okay, we are doing some major cheating here. Because we can't handle rich text strings properly
* we end up getting duplicate strings. To get around this I'm doing do things: 1. Converting rich
* text to normal text and 2. If there's a duplicate I'm adding a space onto the end. Sneaky perhaps
* but it gets the job done until we can handle this a little better.
*/
static public void addToStringTable( BinaryTree strings, Integer integer, UnicodeString string )
{
if (string.isRichText())
string.setOptionFlags( (byte)(string.getOptionFlags() & (~8) ) );
boolean added = false;
while (added == false)
{
try
{
strings.put( integer, string );
added = true;
}
catch( Exception ignore )
{
string.setString( string.getString() + " " );
}
}
}
private int calculateCharCount( final int byte_count )
{
return byte_count / ( wideChar ? LittleEndianConsts.SHORT_SIZE
: LittleEndianConsts.BYTE_SIZE );
}
/**
* 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:
* <P>
* <OL>
* <LI>The string counts at the beginning of the SST record are
* not in the Continue record
* <LI>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
* </OL>
*
* @param record the Continue record's byte data
*/
public void processContinueRecord( final byte[] record )
{
if ( getExpectedChars() == 0 )
{
unfinishedString = "";
totalLengthBytes = 0;
stringDataOffset = 0;
wideChar = false;
manufactureStrings( record, 0, (short) record.length );
}
else
{
int data_length = record.length - LittleEndianConsts.BYTE_SIZE;
if ( calculateByteCount( getExpectedChars() ) > data_length )
{
// create artificial data to create a UnicodeString
byte[] input =
new byte[record.length + LittleEndianConsts.SHORT_SIZE];
short size = (short) ( ( ( record[0] & 1 ) == 1 )
? ( data_length / LittleEndianConsts.SHORT_SIZE )
: ( data_length / LittleEndianConsts.BYTE_SIZE ) );
LittleEndian.putShort( input, (byte) 0, size );
System.arraycopy( record, 0, input, LittleEndianConsts.SHORT_SIZE, record.length );
UnicodeString ucs = new UnicodeString( UnicodeString.sid, (short) input.length, input );
unfinishedString = unfinishedString + ucs.getString();
setExpectedChars( getExpectedChars() - size );
}
else
{
setupStringParameters( record, -LittleEndianConsts.SHORT_SIZE,
getExpectedChars() );
byte[] str_data = new byte[totalLengthBytes];
int length = SSTRecord.STRING_MINIMAL_OVERHEAD
+ ( calculateByteCount( getExpectedChars() ) );
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.
System.arraycopy( record, 0, str_data,
LittleEndianConsts.SHORT_SIZE,
str_data.length
- LittleEndianConsts.SHORT_SIZE );
// write the string length
LittleEndian.putShort( bstring, 0,
(short) getExpectedChars() );
// 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, stringDataOffset, bstring,
SSTRecord.STRING_MINIMAL_OVERHEAD,
bstring.length - SSTRecord.STRING_MINIMAL_OVERHEAD );
// use special constructor to create the final string
UnicodeString string =
new UnicodeString( UnicodeString.sid,
(short) bstring.length, bstring,
unfinishedString );
Integer integer = new Integer( strings.size() );
// field_3_strings.put( integer, string );
addToStringTable( strings, integer, string );
manufactureStrings( record, totalLengthBytes - LittleEndianConsts.SHORT_SIZE, (short) record.length );
}
}
}
/**
* @return the number of characters we expect in the first
* sub-record in a subsequent continuation record
*/
int getExpectedChars()
{
return continuationExpectedChars;
}
private void setExpectedChars( final int count )
{
continuationExpectedChars = count;
}
private int calculateByteCount( final int character_count )
{
return character_count * ( wideChar ? LittleEndianConsts.SHORT_SIZE : LittleEndianConsts.BYTE_SIZE );
}
/**
* @return the unfinished string
*/
String getUnfinishedString()
{
return unfinishedString;
}
/**
* @return the total length of the current string
*/
int getTotalLength()
{
return totalLengthBytes;
}
/**
* @return offset into current string data
*/
int getStringDataOffset()
{
return stringDataOffset;
}
/**
* @return true if current string uses wide characters
*/
boolean isWideChar()
{
return wideChar;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,356 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache POI" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache POI", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.poi.hssf.record;
import org.apache.poi.util.BinaryTree;
import org.apache.poi.util.LittleEndianConsts;
import java.util.List;
import java.util.ArrayList;
/**
* This class handles serialization of SST records. It utilizes the record processor
* class write individual records. This has been refactored from the SSTRecord class.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
class SSTSerializer
{
private List recordLengths;
private BinaryTree strings;
private int numStrings;
private int numUniqueStrings;
private SSTRecordHeader sstRecordHeader;
public SSTSerializer( List recordLengths, BinaryTree strings, int numStrings, int numUniqueStrings )
{
this.recordLengths = recordLengths;
this.strings = strings;
this.numStrings = numStrings;
this.numUniqueStrings = numUniqueStrings;
this.sstRecordHeader = new SSTRecordHeader(numStrings, numUniqueStrings);
}
/**
* Create a byte array consisting of an SST record and any
* required Continue records, ready to be written out.
* <p>
* 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.
*
* @return the byte array
*/
public int serialize( int offset, byte[] data )
{
int record_size = getRecordSize();
int record_length_index = 0;
if ( calculateUnicodeSize() > SSTRecord.MAX_DATA_SPACE )
serializeLargeRecord( record_size, record_length_index, data, offset );
else
serializeSingleSSTRecord( data, offset, record_length_index );
return record_size;
}
private int calculateUnicodeSize()
{
int retval = 0;
for ( int k = 0; k < strings.size(); k++ )
{
retval += getUnicodeString(k).getRecordSize();
}
return retval;
}
// we can probably simplify this later...this calculates the size
// w/o serializing but still is a bit slow
public int getRecordSize()
{
recordLengths = new ArrayList();
int retval = 0;
int unicodesize = calculateUnicodeSize();
if ( unicodesize > SSTRecord.MAX_DATA_SPACE )
{
retval = calcRecordSizesForLongStrings( unicodesize );
}
else
{
// short data: write one simple SST record
retval = SSTRecord.SST_RECORD_OVERHEAD + unicodesize;
recordLengths.add( new Integer( unicodesize ) );
}
return retval;
}
private int calcRecordSizesForLongStrings( int unicodesize )
{
int retval;
UnicodeString unistr = null;
int stringreminant = 0;
int unipos = 0;
boolean lastneedcontinue = false;
int stringbyteswritten = 0;
boolean finished = false;
boolean first_record = true;
int totalWritten = 0;
while ( !finished )
{
int record = 0;
int pos = 0;
if ( first_record )
{
// writing SST record
record = SSTRecord.MAX_RECORD_SIZE;
pos = 12;
first_record = false;
recordLengths.add( new Integer( record - SSTRecord.STD_RECORD_OVERHEAD ) );
}
else
{
// writing continue record
pos = 0;
int to_be_written = ( unicodesize - stringbyteswritten ) + ( lastneedcontinue ? 1 : 0 );
int size = Math.min( SSTRecord.MAX_RECORD_SIZE - SSTRecord.STD_RECORD_OVERHEAD, to_be_written );
if ( size == to_be_written )
{
finished = true;
}
record = size + SSTRecord.STD_RECORD_OVERHEAD;
recordLengths.add( new Integer( size ) );
pos = 4;
}
if ( lastneedcontinue )
{
int available = SSTRecord.MAX_RECORD_SIZE - pos;
if ( stringreminant <= available )
{
// write reminant
stringbyteswritten += stringreminant - 1;
pos += stringreminant;
lastneedcontinue = false;
}
else
{
// write as much of the remnant as possible
int toBeWritten = unistr.maxBrokenLength( available );
if ( available != toBeWritten )
{
int shortrecord = record - ( available - toBeWritten );
recordLengths.set( recordLengths.size() - 1,
new Integer( shortrecord - SSTRecord.STD_RECORD_OVERHEAD ) );
record = shortrecord;
}
stringbyteswritten += toBeWritten - 1;
pos += toBeWritten;
stringreminant -= toBeWritten - 1;
lastneedcontinue = true;
}
}
for ( ; unipos < strings.size(); unipos++ )
{
int available = SSTRecord.MAX_RECORD_SIZE - pos;
Integer intunipos = new Integer( unipos );
unistr = ( (UnicodeString) strings.get( intunipos ) );
if ( unistr.getRecordSize() <= available )
{
stringbyteswritten += unistr.getRecordSize();
pos += unistr.getRecordSize();
}
else
{
if ( available >= SSTRecord.STRING_MINIMAL_OVERHEAD )
{
int toBeWritten =
unistr.maxBrokenLength( available );
stringbyteswritten += toBeWritten;
stringreminant =
( unistr.getRecordSize() - toBeWritten )
+ LittleEndianConsts.BYTE_SIZE;
if ( available != toBeWritten )
{
int shortrecord = record
- ( available - toBeWritten );
recordLengths.set(
recordLengths.size() - 1,
new Integer(
shortrecord - SSTRecord.STD_RECORD_OVERHEAD ) );
record = shortrecord;
}
lastneedcontinue = true;
unipos++;
}
else
{
int shortrecord = record - available;
recordLengths.set( recordLengths.size() - 1,
new Integer( shortrecord - SSTRecord.STD_RECORD_OVERHEAD ) );
record = shortrecord;
}
break;
}
}
totalWritten += record;
}
retval = totalWritten;
return retval;
}
private void serializeSingleSSTRecord( byte[] data, int offset, int record_length_index )
{
// short data: write one simple SST record
int len = ( (Integer) recordLengths.get( record_length_index++ ) ).intValue();
int recordSize = SSTRecord.SST_RECORD_OVERHEAD + len - SSTRecord.STD_RECORD_OVERHEAD;
sstRecordHeader.writeSSTHeader( data, 0 + offset, recordSize );
int pos = SSTRecord.SST_RECORD_OVERHEAD;
for ( int k = 0; k < strings.size(); k++ )
{
// UnicodeString unistr = ( (UnicodeString) strings.get( new Integer( k ) ) );
System.arraycopy( getUnicodeString(k).serialize(), 0, data, pos + offset, getUnicodeString(k).getRecordSize() );
pos += getUnicodeString(k).getRecordSize();
}
}
/**
* Large records are serialized to an SST and to one or more CONTINUE records. Joy. They have the special
* characteristic that they can change the option field when a single string is split across to a
* CONTINUE record.
*/
private void serializeLargeRecord( int record_size, int record_length_index, byte[] buffer, int offset )
{
byte[] stringReminant = null;
int stringIndex = 0;
boolean lastneedcontinue = false;
boolean first_record = true;
int totalWritten = 0;
while ( totalWritten != record_size )
{
int recordLength = ( (Integer) recordLengths.get( record_length_index++ ) ).intValue();
RecordProcessor recordProcessor = new RecordProcessor( buffer,
recordLength, numStrings, numUniqueStrings );
// write the appropriate header
recordProcessor.writeRecordHeader( offset, totalWritten, recordLength, first_record );
first_record = false;
// now, write the rest of the data into the current
// record space
if ( lastneedcontinue )
{
lastneedcontinue = stringReminant.length > recordProcessor.getAvailable();
// the last string in the previous record was not written out completely
stringReminant = recordProcessor.writeStringRemainder( lastneedcontinue,
stringReminant, offset, totalWritten );
}
// last string's remnant, if any, is cleaned up as best as can be done ... now let's try and write
// some more strings
for ( ; stringIndex < strings.size(); stringIndex++ )
{
UnicodeString unistr = getUnicodeString( stringIndex );
if ( unistr.getRecordSize() <= recordProcessor.getAvailable() )
{
recordProcessor.writeWholeString( unistr, offset, totalWritten );
}
else
{
// can't write the entire string out
if ( recordProcessor.getAvailable() >= SSTRecord.STRING_MINIMAL_OVERHEAD )
{
// we can write some of it
stringReminant = recordProcessor.writePartString( unistr, offset, totalWritten );
lastneedcontinue = true;
stringIndex++;
}
break;
}
}
totalWritten += recordLength + SSTRecord.STD_RECORD_OVERHEAD;
}
}
private UnicodeString getUnicodeString( int index )
{
Integer intunipos = new Integer( index );
return ( (UnicodeString) strings.get( intunipos ) );
}
}

View File

@ -66,6 +66,7 @@ import org.apache.poi.util.StringUtil;
* REFERENCE: PG 264 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver
* @author Marc Johnson (mjohnson at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @version 2.0-pre
*/
@ -77,12 +78,28 @@ public class UnicodeString
private short field_1_charCount; // = 0;
private byte field_2_optionflags; // = 0;
private String field_3_string; // = null;
private final int RICH_TEXT_BIT = 8;
public UnicodeString()
{
}
public int hashCode()
{
return field_1_charCount;
int stringHash = 0;
if (field_3_string != null)
stringHash = field_3_string.hashCode();
return field_1_charCount + stringHash;
}
/**
* Our handling of equals is inconsistent with compareTo. The trouble is because we don't truely understand
* rich text fields yet it's difficult to make a sound comparison.
*
* @param o The object to compare.
* @return true if the object is actually equal.
*/
public boolean equals(Object o)
{
if ((o == null) || (o.getClass() != this.getClass()))
@ -96,10 +113,6 @@ public class UnicodeString
&& field_3_string.equals(other.field_3_string));
}
public UnicodeString()
{
}
/**
* construct a unicode string record and fill its fields, ID is ignored
* @param id - ignored
@ -278,19 +291,10 @@ public class UnicodeString
public int serialize(int offset, byte [] data)
{
int charsize = 1;
if (getOptionFlags() == 1)
{
charsize = 2;
}
// byte[] retval = new byte[ 3 + (getString().length() * charsize) ];
LittleEndian.putShort(data, 0 + offset, getCharCount());
data[ 2 + offset ] = getOptionFlags();
// System.out.println("Unicode: We've got "+retval[2]+" for our option flag");
if (getOptionFlags() == 0)
if (!isUncompressedUnicode())
{
StringUtil.putCompressedUnicode(getString(), data, 0x3 + offset);
}
@ -302,14 +306,14 @@ public class UnicodeString
return getRecordSize();
}
private boolean isUncompressedUnicode()
{
return (getOptionFlags() & 0x01) == 1;
}
public int getRecordSize()
{
int charsize = 1;
if (getOptionFlags() == 1)
{
charsize = 2;
}
int charsize = isUncompressedUnicode() ? 2 : 1;
return 3 + (getString().length() * charsize);
}
@ -338,11 +342,16 @@ public class UnicodeString
return this.getString().compareTo(str.getString());
}
public boolean isRichText()
{
return (getOptionFlags() & RICH_TEXT_BIT) != 0;
}
int maxBrokenLength(final int proposedBrokenLength)
{
int rval = proposedBrokenLength;
if ((field_2_optionflags & 1) == 1)
if (isUncompressedUnicode())
{
int proposedStringLength = proposedBrokenLength - 3;
@ -355,12 +364,4 @@ public class UnicodeString
return rval;
}
// public boolean equals(Object obj) {
// if (!(obj instanceof UnicodeString)) return false;
//
// UnicodeString str = (UnicodeString)obj;
//
//
// return this.getString().equals(str.getString());
// }
}

View File

@ -126,8 +126,8 @@ public class HSSFRow
this.sheet = sheet;
row = new RowRecord();
row.setHeight((short) 0xff);
row.setLastCol((short)-1);
row.setFirstCol((short)-1);
row.setLastCol((short) -1);
row.setFirstCol((short) -1);
// row.setRowNumber(rowNum);
setRowNum(rowNum);
@ -213,11 +213,11 @@ public class HSSFRow
if (cell.getCellNum() == row.getLastCol())
{
row.setLastCol( findLastCell(row.getLastCol()) );
row.setLastCol(findLastCell(row.getLastCol()));
}
if (cell.getCellNum() == row.getFirstCol())
{
row.setFirstCol( findFirstCell(row.getFirstCol()) );
row.setFirstCol(findFirstCell(row.getFirstCol()));
}
}
@ -270,11 +270,11 @@ public class HSSFRow
{
if (row.getFirstCol() == -1)
{
row.setFirstCol( cell.getCellNum() );
row.setFirstCol(cell.getCellNum());
}
if (row.getLastCol() == -1)
{
row.setLastCol( cell.getCellNum() );
row.setLastCol(cell.getCellNum());
}
cells.put(new Integer(cell.getCellNum()), cell);
@ -292,8 +292,8 @@ public class HSSFRow
* get the hssfcell representing a given column (logical cell) 0-based. If you
* ask for a cell that is not defined....you get a null.
*
* @param cellnum - 0 based column number
* @returns HSSFCell representing that column or null if undefined.
* @param cellnum 0 based column number
* @return HSSFCell representing that column or null if undefined.
*/
public HSSFCell getCell(short cellnum)
@ -318,7 +318,10 @@ public class HSSFRow
public short getFirstCellNum()
{
return row.getFirstCol();
if (getPhysicalNumberOfCells() == 0)
return -1;
else
return row.getFirstCol();
}
/**
@ -328,7 +331,10 @@ public class HSSFRow
public short getLastCellNum()
{
return row.getLastCol();
if (getPhysicalNumberOfCells() == 0)
return -1;
else
return row.getLastCol();
}
@ -441,7 +447,7 @@ public class HSSFRow
}
/**
* @returns cell iterator of the physically defined cells. Note element 4 may
* @return cell iterator of the physically defined cells. Note element 4 may
* actually be row cell depending on how many are defined!
*/

View File

@ -1,4 +1,3 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
@ -60,11 +59,14 @@
*/
package org.apache.poi.hssf.usermodel;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WSBoolRecord;
import org.apache.poi.hssf.util.Region;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import java.util.Iterator;
@ -74,12 +76,12 @@ import java.util.TreeMap;
* High level representation of a worksheet.
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @version 1.0-pre
* @author Libin Roman (romal at vistaportal.com)
*/
public class HSSFSheet
{
private static final int DEBUG = POILogger.DEBUG;
private static final int DEBUG = POILogger.DEBUG;
/**
* Used for compile-time optimization. This is the initial size for the collection of
@ -87,17 +89,17 @@ public class HSSFSheet
* by setting this to a higher number and recompiling a custom edition of HSSFSheet.
*/
public final static int INITIAL_CAPACITY = 20;
public final static int INITIAL_CAPACITY = 20;
/**
* reference to the low level Sheet object
*/
private Sheet sheet;
private TreeMap rows;
private Workbook book;
private int firstrow;
private int lastrow;
private Sheet sheet;
private TreeMap rows;
private Workbook book;
private int firstrow;
private int lastrow;
private static POILogger log = POILogFactory.getLogger(HSSFSheet.class);
/**
@ -110,8 +112,8 @@ public class HSSFSheet
protected HSSFSheet(Workbook book)
{
sheet = Sheet.createSheet();
rows = new TreeMap(); // new ArrayList(INITIAL_CAPACITY);
sheet = Sheet.createSheet();
rows = new TreeMap(); // new ArrayList(INITIAL_CAPACITY);
this.book = book;
}
@ -127,16 +129,11 @@ public class HSSFSheet
protected HSSFSheet(Workbook book, Sheet sheet)
{
this.sheet = sheet;
rows = new TreeMap();
this.book = book;
rows = new TreeMap();
this.book = book;
setPropertiesFromSheet(sheet);
}
/** private default constructor prevents bogus initializationless construction */
private HSSFSheet()
{
}
/**
* used internally to set the properties given a Sheet object
@ -144,8 +141,8 @@ public class HSSFSheet
private void setPropertiesFromSheet(Sheet sheet)
{
int sloc = sheet.getLoc();
RowRecord row = sheet.getNextRow();
int sloc = sheet.getLoc();
RowRecord row = sheet.getNextRow();
while (row != null)
{
@ -154,8 +151,8 @@ public class HSSFSheet
row = sheet.getNextRow();
}
sheet.setLoc(sloc);
CellValueRecordInterface cval = sheet.getNextValueRecord();
long timestart = System.currentTimeMillis();
CellValueRecordInterface cval = sheet.getNextValueRecord();
long timestart = System.currentTimeMillis();
log.log(DEBUG, "Time at start of cell creating in HSSF sheet = ",
new Long(timestart));
@ -163,8 +160,8 @@ public class HSSFSheet
while (cval != null)
{
long cellstart = System.currentTimeMillis();
HSSFRow hrow = lastrow;
long cellstart = System.currentTimeMillis();
HSSFRow hrow = lastrow;
if ((lastrow == null) || (lastrow.getRowNum() != cval.getRow()))
{
@ -236,10 +233,10 @@ public class HSSFSheet
while (iter.hasNext())
{
HSSFCell cell = ( HSSFCell ) iter.next();
HSSFCell cell = (HSSFCell) iter.next();
sheet.removeValueRecord(row.getRowNum(),
cell.getCellValueRecord());
cell.getCellValueRecord());
}
sheet.removeRow(row.getRowRecord());
}
@ -251,10 +248,10 @@ public class HSSFSheet
private int findLastRow(int lastrow)
{
int rownum = lastrow - 1;
HSSFRow r = getRow(rownum);
int rownum = lastrow - 1;
HSSFRow r = getRow(rownum);
while (r == null)
while (r == null && rownum >= 0)
{
r = getRow(--rownum);
}
@ -267,13 +264,17 @@ public class HSSFSheet
private int findFirstRow(int firstrow)
{
int rownum = firstrow + 1;
HSSFRow r = getRow(rownum);
int rownum = firstrow + 1;
HSSFRow r = getRow(rownum);
while (r == null)
while (r == null && rownum <= getLastRowNum())
{
r = getRow(++rownum);
}
if (rownum > getLastRowNum())
return -1;
return rownum;
}
@ -311,8 +312,8 @@ public class HSSFSheet
{
HSSFRow row = new HSSFRow();
row.setRowNum(( short ) rownum);
return ( HSSFRow ) rows.get(row);
row.setRowNum((short) rownum);
return (HSSFRow) rows.get(row);
}
/**
@ -344,26 +345,6 @@ public class HSSFSheet
return lastrow;
}
/**
* Seems to be unused (gjs)
*
* used internally to add cells from a high level row to the low level model
* @param row the row object to represent in low level RowRecord.
*/
private void addCellsFromRow(HSSFRow row)
{
Iterator iter = row.cellIterator();
// for (int k = 0; k < row.getPhysicalNumberOfCells(); k++)
while (iter.hasNext())
{
HSSFCell cell =
( HSSFCell ) iter.next(); // row.getPhysicalCellAt(k);
sheet.addValueRecord(row.getRowNum(), cell.getCellValueRecord());
}
}
/**
* set the width (in units of 1/256th of a character width)
* @param column - the column to set (0-based)
@ -400,7 +381,7 @@ public class HSSFSheet
/**
* get the default row height for the sheet (if the rows do not define their own height) in
* twips (1/20 of a point)
* @retun default row height
* @return default row height
*/
public short getDefaultRowHeight()
@ -449,7 +430,7 @@ public class HSSFSheet
public void setDefaultRowHeightInPoints(float height)
{
sheet.setDefaultRowHeight(( short ) (height * 20));
sheet.setDefaultRowHeight((short) (height * 20));
}
/**
@ -480,10 +461,10 @@ public class HSSFSheet
public int addMergedRegion(Region region)
{
return sheet.addMergedRegion(( short ) region.getRowFrom(),
region.getColumnFrom(),
( short ) region.getRowTo(),
region.getColumnTo());
return sheet.addMergedRegion((short) region.getRowFrom(),
region.getColumnFrom(),
(short) region.getRowTo(),
region.getColumnTo());
}
/**
@ -494,7 +475,7 @@ public class HSSFSheet
public void setVerticallyCenter(boolean value)
{
VCenterRecord record =
( VCenterRecord ) sheet.findFirstRecordBySid(VCenterRecord.sid);
(VCenterRecord) sheet.findFirstRecordBySid(VCenterRecord.sid);
record.setVCenter(value);
}
@ -506,7 +487,7 @@ public class HSSFSheet
public boolean getVerticallyCenter(boolean value)
{
VCenterRecord record =
( VCenterRecord ) sheet.findFirstRecordBySid(VCenterRecord.sid);
(VCenterRecord) sheet.findFirstRecordBySid(VCenterRecord.sid);
return record.getVCenter();
}
@ -543,7 +524,7 @@ public class HSSFSheet
}
/**
* @returns an iterator of the PHYSICAL rows. Meaning the 3rd element may not
* @return an iterator of the PHYSICAL rows. Meaning the 3rd element may not
* be the third row if say for instance the second row is undefined.
*/
@ -571,7 +552,7 @@ public class HSSFSheet
public void setAlternativeExpression(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setAlternateExpression(b);
}
@ -584,7 +565,7 @@ public class HSSFSheet
public void setAlternativeFormula(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setAlternateFormula(b);
}
@ -597,7 +578,7 @@ public class HSSFSheet
public void setAutobreaks(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setAutobreaks(b);
}
@ -610,7 +591,7 @@ public class HSSFSheet
public void setDialog(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setDialog(b);
}
@ -624,7 +605,7 @@ public class HSSFSheet
public void setDisplayGuts(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setDisplayGuts(b);
}
@ -637,7 +618,7 @@ public class HSSFSheet
public void setFitToPage(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setFitToPage(b);
}
@ -650,7 +631,7 @@ public class HSSFSheet
public void setRowSumsBelow(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setRowSumsBelow(b);
}
@ -663,7 +644,7 @@ public class HSSFSheet
public void setRowSumsRight(boolean b)
{
WSBoolRecord record =
( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid);
(WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid);
record.setRowSumsRight(b);
}
@ -675,8 +656,8 @@ public class HSSFSheet
public boolean getAlternateExpression()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getAlternateExpression();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getAlternateExpression();
}
/**
@ -686,8 +667,8 @@ public class HSSFSheet
public boolean getAlternateFormula()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getAlternateFormula();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getAlternateFormula();
}
/**
@ -697,8 +678,8 @@ public class HSSFSheet
public boolean getAutobreaks()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getAutobreaks();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getAutobreaks();
}
/**
@ -708,8 +689,8 @@ public class HSSFSheet
public boolean getDialog()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getDialog();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getDialog();
}
/**
@ -720,8 +701,8 @@ public class HSSFSheet
public boolean getDisplayGuts()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getDisplayGuts();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getDisplayGuts();
}
/**
@ -731,8 +712,8 @@ public class HSSFSheet
public boolean getFitToPage()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getFitToPage();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getFitToPage();
}
/**
@ -742,8 +723,8 @@ public class HSSFSheet
public boolean getRowSumsBelow()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getRowSumsBelow();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getRowSumsBelow();
}
/**
@ -753,7 +734,7 @@ public class HSSFSheet
public boolean getRowSumsRight()
{
return (( WSBoolRecord ) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getRowSumsRight();
return ((WSBoolRecord) sheet.findFirstRecordBySid(WSBoolRecord.sid))
.getRowSumsRight();
}
}

View File

@ -592,4 +592,17 @@ public class LittleEndian
return copy;
}
/**
* Retrieves and unsigned short. This is converted UP to a int
* so it can fit.
*
* @param data The data to read
* @param offset The offset to read the short from
* @return An integer representation of the short.
*/
public static int getUShort( byte[] data, int offset )
{
return (int)getNumber(data, offset, SHORT_SIZE);
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,3 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
@ -55,24 +54,28 @@
package org.apache.poi.hssf.record;
import org.apache.poi.util.*;
import junit.framework.*;
import junit.framework.TestCase;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import java.io.*;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* @author Marc Johnson (mjohnson at apache dot org)
*/
public class TestSSTRecord
extends TestCase
extends TestCase
{
private String _test_file_path;
private String _test_file_path;
private static final String _test_file_path_property =
"HSSF.testdata.path";
"HSSF.testdata.path";
/**
* Creates new TestSSTRecord
@ -80,10 +83,10 @@ public class TestSSTRecord
* @param name
*/
public TestSSTRecord(String name)
public TestSSTRecord( String name )
{
super(name);
_test_file_path = System.getProperty(_test_file_path_property);
super( name );
_test_file_path = System.getProperty( _test_file_path_property );
}
/**
@ -93,118 +96,118 @@ public class TestSSTRecord
*/
public void testProcessContinueRecord()
throws IOException
throws IOException
{
byte[] testdata = readTestData("BigSSTRecord");
byte[] input = new byte[ testdata.length - 4 ];
byte[] testdata = readTestData( "BigSSTRecord" );
byte[] input = new byte[testdata.length - 4];
System.arraycopy(testdata, 4, input, 0, input.length);
SSTRecord record =
new SSTRecord(LittleEndian.getShort(testdata, 0),
LittleEndian.getShort(testdata, 2), input);
byte[] continueRecord = readTestData("BigSSTRecordCR");
System.arraycopy( testdata, 4, input, 0, input.length );
SSTRecord record =
new SSTRecord( LittleEndian.getShort( testdata, 0 ),
LittleEndian.getShort( testdata, 2 ), input );
byte[] continueRecord = readTestData( "BigSSTRecordCR" );
input = new byte[ continueRecord.length - 4 ];
System.arraycopy(continueRecord, 4, input, 0, input.length);
record.processContinueRecord(input);
assertEquals(1464, record.getNumStrings());
assertEquals(688, record.getNumUniqueStrings());
assertEquals(688, record.countStrings());
input = new byte[continueRecord.length - 4];
System.arraycopy( continueRecord, 4, input, 0, input.length );
record.processContinueRecord( input );
assertEquals( 1464, record.getNumStrings() );
assertEquals( 688, record.getNumUniqueStrings() );
assertEquals( 688, record.countStrings() );
byte[] ser_output = record.serialize();
int offset = 0;
short type = LittleEndian.getShort(ser_output, offset);
int offset = 0;
short type = LittleEndian.getShort( ser_output, offset );
offset += LittleEndianConsts.SHORT_SIZE;
short length = LittleEndian.getShort(ser_output, offset);
short length = LittleEndian.getShort( ser_output, offset );
offset += LittleEndianConsts.SHORT_SIZE;
byte[] recordData = new byte[ length ];
byte[] recordData = new byte[length];
System.arraycopy(ser_output, offset, recordData, 0, length);
System.arraycopy( ser_output, offset, recordData, 0, length );
offset += length;
SSTRecord testRecord = new SSTRecord(type, length, recordData);
SSTRecord testRecord = new SSTRecord( type, length, recordData );
assertEquals(ContinueRecord.sid,
LittleEndian.getShort(ser_output, offset));
assertEquals( ContinueRecord.sid,
LittleEndian.getShort( ser_output, offset ) );
offset += LittleEndianConsts.SHORT_SIZE;
length = LittleEndian.getShort(ser_output, offset);
length = LittleEndian.getShort( ser_output, offset );
offset += LittleEndianConsts.SHORT_SIZE;
byte[] cr = new byte[ length ];
byte[] cr = new byte[length];
System.arraycopy(ser_output, offset, cr, 0, length);
System.arraycopy( ser_output, offset, cr, 0, length );
offset += length;
assertEquals(offset, ser_output.length);
testRecord.processContinueRecord(cr);
assertEquals(record, testRecord);
assertEquals( offset, ser_output.length );
testRecord.processContinueRecord( cr );
assertEquals( record, testRecord );
// testing based on new bug report
testdata = readTestData("BigSSTRecord2");
input = new byte[ testdata.length - 4 ];
System.arraycopy(testdata, 4, input, 0, input.length);
record = new SSTRecord(LittleEndian.getShort(testdata, 0),
LittleEndian.getShort(testdata, 2), input);
byte[] continueRecord1 = readTestData("BigSSTRecord2CR1");
testdata = readTestData( "BigSSTRecord2" );
input = new byte[testdata.length - 4];
System.arraycopy( testdata, 4, input, 0, input.length );
record = new SSTRecord( LittleEndian.getShort( testdata, 0 ),
LittleEndian.getShort( testdata, 2 ), input );
byte[] continueRecord1 = readTestData( "BigSSTRecord2CR1" );
input = new byte[ continueRecord1.length - 4 ];
System.arraycopy(continueRecord1, 4, input, 0, input.length);
record.processContinueRecord(input);
byte[] continueRecord2 = readTestData("BigSSTRecord2CR2");
input = new byte[continueRecord1.length - 4];
System.arraycopy( continueRecord1, 4, input, 0, input.length );
record.processContinueRecord( input );
byte[] continueRecord2 = readTestData( "BigSSTRecord2CR2" );
input = new byte[ continueRecord2.length - 4 ];
System.arraycopy(continueRecord2, 4, input, 0, input.length);
record.processContinueRecord(input);
byte[] continueRecord3 = readTestData("BigSSTRecord2CR3");
input = new byte[continueRecord2.length - 4];
System.arraycopy( continueRecord2, 4, input, 0, input.length );
record.processContinueRecord( input );
byte[] continueRecord3 = readTestData( "BigSSTRecord2CR3" );
input = new byte[ continueRecord3.length - 4 ];
System.arraycopy(continueRecord3, 4, input, 0, input.length);
record.processContinueRecord(input);
byte[] continueRecord4 = readTestData("BigSSTRecord2CR4");
input = new byte[continueRecord3.length - 4];
System.arraycopy( continueRecord3, 4, input, 0, input.length );
record.processContinueRecord( input );
byte[] continueRecord4 = readTestData( "BigSSTRecord2CR4" );
input = new byte[ continueRecord4.length - 4 ];
System.arraycopy(continueRecord4, 4, input, 0, input.length);
record.processContinueRecord(input);
byte[] continueRecord5 = readTestData("BigSSTRecord2CR5");
input = new byte[continueRecord4.length - 4];
System.arraycopy( continueRecord4, 4, input, 0, input.length );
record.processContinueRecord( input );
byte[] continueRecord5 = readTestData( "BigSSTRecord2CR5" );
input = new byte[ continueRecord5.length - 4 ];
System.arraycopy(continueRecord5, 4, input, 0, input.length);
record.processContinueRecord(input);
byte[] continueRecord6 = readTestData("BigSSTRecord2CR6");
input = new byte[continueRecord5.length - 4];
System.arraycopy( continueRecord5, 4, input, 0, input.length );
record.processContinueRecord( input );
byte[] continueRecord6 = readTestData( "BigSSTRecord2CR6" );
input = new byte[ continueRecord6.length - 4 ];
System.arraycopy(continueRecord6, 4, input, 0, input.length);
record.processContinueRecord(input);
byte[] continueRecord7 = readTestData("BigSSTRecord2CR7");
input = new byte[continueRecord6.length - 4];
System.arraycopy( continueRecord6, 4, input, 0, input.length );
record.processContinueRecord( input );
byte[] continueRecord7 = readTestData( "BigSSTRecord2CR7" );
input = new byte[ continueRecord7.length - 4 ];
System.arraycopy(continueRecord7, 4, input, 0, input.length);
record.processContinueRecord(input);
assertEquals(158642, record.getNumStrings());
assertEquals(5249, record.getNumUniqueStrings());
assertEquals(5249, record.countStrings());
input = new byte[continueRecord7.length - 4];
System.arraycopy( continueRecord7, 4, input, 0, input.length );
record.processContinueRecord( input );
assertEquals( 158642, record.getNumStrings() );
assertEquals( 5249, record.getNumUniqueStrings() );
assertEquals( 5249, record.countStrings() );
ser_output = record.serialize();
offset = 0;
type = LittleEndian.getShort(ser_output, offset);
offset += LittleEndianConsts.SHORT_SIZE;
length = LittleEndian.getShort(ser_output, offset);
offset += LittleEndianConsts.SHORT_SIZE;
recordData = new byte[ length ];
System.arraycopy(ser_output, offset, recordData, 0, length);
offset += length;
testRecord = new SSTRecord(type, length, recordData);
for (int count = 0; count < 7; count++)
offset = 0;
type = LittleEndian.getShort( ser_output, offset );
offset += LittleEndianConsts.SHORT_SIZE;
length = LittleEndian.getShort( ser_output, offset );
offset += LittleEndianConsts.SHORT_SIZE;
recordData = new byte[length];
System.arraycopy( ser_output, offset, recordData, 0, length );
offset += length;
testRecord = new SSTRecord( type, length, recordData );
for ( int count = 0; count < 7; count++ )
{
assertEquals(ContinueRecord.sid,
LittleEndian.getShort(ser_output, offset));
assertEquals( ContinueRecord.sid,
LittleEndian.getShort( ser_output, offset ) );
offset += LittleEndianConsts.SHORT_SIZE;
length = LittleEndian.getShort(ser_output, offset);
length = LittleEndian.getShort( ser_output, offset );
offset += LittleEndianConsts.SHORT_SIZE;
cr = new byte[ length ];
System.arraycopy(ser_output, offset, cr, 0, length);
testRecord.processContinueRecord(cr);
cr = new byte[length];
System.arraycopy( ser_output, offset, cr, 0, length );
testRecord.processContinueRecord( cr );
offset += length;
}
assertEquals(offset, ser_output.length);
assertEquals(record, testRecord);
assertEquals( offset, ser_output.length );
assertEquals( record, testRecord );
}
/**
@ -214,23 +217,23 @@ public class TestSSTRecord
*/
public void testHugeStrings()
throws IOException
throws IOException
{
SSTRecord record = new SSTRecord();
byte[][] bstrings =
{
new byte[ 9000 ], new byte[ 7433 ], new byte[ 9002 ],
new byte[ 16998 ]
};
String[] strings = new String[ bstrings.length ];
int total_length = 0;
SSTRecord record = new SSTRecord();
byte[][] bstrings =
{
new byte[9000], new byte[7433], new byte[9002],
new byte[16998]
};
String[] strings = new String[bstrings.length];
int total_length = 0;
for (int k = 0; k < bstrings.length; k++)
for ( int k = 0; k < bstrings.length; k++ )
{
Arrays.fill(bstrings[ k ], ( byte ) ('a' + k));
strings[ k ] = new String(bstrings[ k ]);
record.addString(strings[ k ]);
total_length += 3 + bstrings[ k ].length;
Arrays.fill( bstrings[k], (byte) ( 'a' + k ) );
strings[k] = new String( bstrings[k] );
record.addString( strings[k] );
total_length += 3 + bstrings[k].length;
}
// add overhead of SST record
@ -240,88 +243,88 @@ public class TestSSTRecord
total_length += 4;
// add overhead of six records
total_length += (6 * 4);
byte[] content = new byte[ record.getRecordSize() ];
total_length += ( 6 * 4 );
byte[] content = new byte[record.getRecordSize()];
record.serialize(0, content);
assertEquals(total_length, content.length);
for (int index = 0; index != content.length; )
record.serialize( 0, content );
assertEquals( total_length, content.length );
for ( int index = 0; index != content.length; )
{
short record_type = LittleEndian.getShort(content, index);
short record_type = LittleEndian.getShort( content, index );
index += LittleEndianConsts.SHORT_SIZE;
short record_length = LittleEndian.getShort(content, index);
short record_length = LittleEndian.getShort( content, index );
index += LittleEndianConsts.SHORT_SIZE;
byte[] data = new byte[ record_length ];
byte[] data = new byte[record_length];
System.arraycopy(content, index, data, 0, record_length);
System.arraycopy( content, index, data, 0, record_length );
index += record_length;
if (record_type == SSTRecord.sid)
if ( record_type == SSTRecord.sid )
{
record = new SSTRecord(record_type, record_length, data);
record = new SSTRecord( record_type, record_length, data );
}
else
{
record.processContinueRecord(data);
record.processContinueRecord( data );
}
}
assertEquals(strings.length, record.getNumStrings());
assertEquals(strings.length, record.getNumUniqueStrings());
assertEquals(strings.length, record.countStrings());
for (int k = 0; k < strings.length; k++)
assertEquals( strings.length, record.getNumStrings() );
assertEquals( strings.length, record.getNumUniqueStrings() );
assertEquals( strings.length, record.countStrings() );
for ( int k = 0; k < strings.length; k++ )
{
assertEquals(strings[ k ], record.getString(k));
assertEquals( strings[k], record.getString( k ) );
}
record = new SSTRecord();
bstrings[ 1 ] = new byte[ bstrings[ 1 ].length - 1 ];
for (int k = 0; k < bstrings.length; k++)
record = new SSTRecord();
bstrings[1] = new byte[bstrings[1].length - 1];
for ( int k = 0; k < bstrings.length; k++ )
{
if ((bstrings[ k ].length % 2) == 1)
if ( ( bstrings[k].length % 2 ) == 1 )
{
Arrays.fill(bstrings[ k ], ( byte ) ('a' + k));
strings[ k ] = new String(bstrings[ k ]);
Arrays.fill( bstrings[k], (byte) ( 'a' + k ) );
strings[k] = new String( bstrings[k] );
}
else
{
char[] data = new char[ bstrings[ k ].length / 2 ];
char[] data = new char[bstrings[k].length / 2];
Arrays.fill(data, ( char ) ('\u2122' + k));
strings[ k ] = new String(data);
Arrays.fill( data, (char) ( '\u2122' + k ) );
strings[k] = new String( data );
}
record.addString(strings[ k ]);
record.addString( strings[k] );
}
content = new byte[ record.getRecordSize() ];
record.serialize(0, content);
content = new byte[record.getRecordSize()];
record.serialize( 0, content );
total_length--;
assertEquals(total_length, content.length);
for (int index = 0; index != content.length; )
assertEquals( total_length, content.length );
for ( int index = 0; index != content.length; )
{
short record_type = LittleEndian.getShort(content, index);
short record_type = LittleEndian.getShort( content, index );
index += LittleEndianConsts.SHORT_SIZE;
short record_length = LittleEndian.getShort(content, index);
short record_length = LittleEndian.getShort( content, index );
index += LittleEndianConsts.SHORT_SIZE;
byte[] data = new byte[ record_length ];
byte[] data = new byte[record_length];
System.arraycopy(content, index, data, 0, record_length);
System.arraycopy( content, index, data, 0, record_length );
index += record_length;
if (record_type == SSTRecord.sid)
if ( record_type == SSTRecord.sid )
{
record = new SSTRecord(record_type, record_length, data);
record = new SSTRecord( record_type, record_length, data );
}
else
{
record.processContinueRecord(data);
record.processContinueRecord( data );
}
}
assertEquals(strings.length, record.getNumStrings());
assertEquals(strings.length, record.getNumUniqueStrings());
assertEquals(strings.length, record.countStrings());
for (int k = 0; k < strings.length; k++)
assertEquals( strings.length, record.getNumStrings() );
assertEquals( strings.length, record.getNumUniqueStrings() );
assertEquals( strings.length, record.countStrings() );
for ( int k = 0; k < strings.length; k++ )
{
assertEquals(strings[ k ], record.getString(k));
assertEquals( strings[k], record.getString( k ) );
}
}
@ -332,7 +335,7 @@ public class TestSSTRecord
*/
public void testSSTRecordBug()
throws IOException
throws IOException
{
// create an SSTRecord and write a certain pattern of strings
@ -342,22 +345,22 @@ public class TestSSTRecord
// the record will start with two integers, then this string
// ... that will eat up 16 of the 8224 bytes that the record
// can hold
record.addString("Hello");
record.addString( "Hello" );
// now we have an additional 8208 bytes, which is an exact
// multiple of 16 bytes
long testvalue = 1000000000000L;
for (int k = 0; k < 2000; k++)
for ( int k = 0; k < 2000; k++ )
{
record.addString(String.valueOf(testvalue++));
record.addString( String.valueOf( testvalue++ ) );
}
byte[] content = new byte[ record.getRecordSize() ];
byte[] content = new byte[record.getRecordSize()];
record.serialize(0, content);
assertEquals(( byte ) 13, content[ 4 + 8228 ]);
assertEquals(( byte ) 13, content[ 4 + 8228 * 2 ]);
assertEquals(( byte ) 13, content[ 4 + 8228 * 3 ]);
record.serialize( 0, content );
assertEquals( (byte) 13, content[4 + 8228] );
assertEquals( (byte) 13, content[4 + 8228 * 2] );
assertEquals( (byte) 13, content[4 + 8228 * 3] );
}
/**
@ -367,43 +370,43 @@ public class TestSSTRecord
public void testSimpleAddString()
{
SSTRecord record = new SSTRecord();
String s1 = "Hello world";
String s1 = "Hello world";
// \u2122 is the encoding of the trademark symbol ...
String s2 = "Hello world\u2122";
String s2 = "Hello world\u2122";
assertEquals(0, record.addString(s1));
assertEquals(s1, record.getString(0));
assertEquals(1, record.countStrings());
assertEquals(1, record.getNumStrings());
assertEquals(1, record.getNumUniqueStrings());
assertEquals(0, record.addString(s1));
assertEquals(s1, record.getString(0));
assertEquals(1, record.countStrings());
assertEquals(2, record.getNumStrings());
assertEquals(1, record.getNumUniqueStrings());
assertEquals(1, record.addString(s2));
assertEquals(s2, record.getString(1));
assertEquals(2, record.countStrings());
assertEquals(3, record.getNumStrings());
assertEquals(2, record.getNumUniqueStrings());
assertEquals( 0, record.addString( s1 ) );
assertEquals( s1, record.getString( 0 ) );
assertEquals( 1, record.countStrings() );
assertEquals( 1, record.getNumStrings() );
assertEquals( 1, record.getNumUniqueStrings() );
assertEquals( 0, record.addString( s1 ) );
assertEquals( s1, record.getString( 0 ) );
assertEquals( 1, record.countStrings() );
assertEquals( 2, record.getNumStrings() );
assertEquals( 1, record.getNumUniqueStrings() );
assertEquals( 1, record.addString( s2 ) );
assertEquals( s2, record.getString( 1 ) );
assertEquals( 2, record.countStrings() );
assertEquals( 3, record.getNumStrings() );
assertEquals( 2, record.getNumUniqueStrings() );
Iterator iter = record.getStrings();
while (iter.hasNext())
while ( iter.hasNext() )
{
UnicodeString ucs = ( UnicodeString ) iter.next();
UnicodeString ucs = (UnicodeString) iter.next();
if (ucs.getString().equals(s1))
if ( ucs.getString().equals( s1 ) )
{
assertEquals(( byte ) 0, ucs.getOptionFlags());
assertEquals( (byte) 0, ucs.getOptionFlags() );
}
else if (ucs.getString().equals(s2))
else if ( ucs.getString().equals( s2 ) )
{
assertEquals(( byte ) 1, ucs.getOptionFlags());
assertEquals( (byte) 1, ucs.getOptionFlags() );
}
else
{
fail("cannot match string: " + ucs.getString());
fail( "cannot match string: " + ucs.getString() );
}
}
}
@ -415,25 +418,25 @@ public class TestSSTRecord
*/
public void testReaderConstructor()
throws IOException
throws IOException
{
byte[] testdata = readTestData("BigSSTRecord");
byte[] input = new byte[ testdata.length - 4 ];
byte[] testdata = readTestData( "BigSSTRecord" );
byte[] input = new byte[testdata.length - 4];
System.arraycopy(testdata, 4, input, 0, input.length);
SSTRecord record = new SSTRecord(LittleEndian.getShort(testdata, 0),
LittleEndian.getShort(testdata, 2),
input);
System.arraycopy( testdata, 4, input, 0, input.length );
SSTRecord record = new SSTRecord( LittleEndian.getShort( testdata, 0 ),
LittleEndian.getShort( testdata, 2 ),
input );
assertEquals(1464, record.getNumStrings());
assertEquals(688, record.getNumUniqueStrings());
assertEquals(492, record.countStrings());
assertEquals(1, record.getExpectedChars());
assertEquals("Consolidated B-24J Liberator The Dragon & His Tai",
record.getUnfinishedString());
assertEquals(52, record.getTotalLength());
assertEquals(3, record.getStringDataOffset());
assertTrue(!record.isWideChar());
assertEquals( 1464, record.getNumStrings() );
assertEquals( 688, record.getNumUniqueStrings() );
assertEquals( 492, record.countStrings() );
assertEquals( 1, record.getDeserializer().getExpectedChars() );
assertEquals( "Consolidated B-24J Liberator The Dragon & His Tai",
record.getDeserializer().getUnfinishedString() );
assertEquals( 52, record.getDeserializer().getTotalLength() );
assertEquals( 3, record.getDeserializer().getStringDataOffset() );
assertTrue( !record.getDeserializer().isWideChar() );
}
/**
@ -444,26 +447,26 @@ public class TestSSTRecord
{
SSTRecord record = new SSTRecord();
assertEquals(0, record.getNumStrings());
assertEquals(0, record.getNumUniqueStrings());
assertEquals(0, record.countStrings());
assertEquals(0, record.getExpectedChars());
assertEquals("", record.getUnfinishedString());
assertEquals(0, record.getTotalLength());
assertEquals(0, record.getStringDataOffset());
assertTrue(!record.isWideChar());
byte[] output = record.serialize();
assertEquals( 0, record.getNumStrings() );
assertEquals( 0, record.getNumUniqueStrings() );
assertEquals( 0, record.countStrings() );
assertEquals( 0, record.getDeserializer().getExpectedChars() );
assertEquals( "", record.getDeserializer().getUnfinishedString() );
assertEquals( 0, record.getDeserializer().getTotalLength() );
assertEquals( 0, record.getDeserializer().getStringDataOffset() );
assertTrue( !record.getDeserializer().isWideChar() );
byte[] output = record.serialize();
byte[] expected =
{
( byte ) record.getSid(), ( byte ) (record.getSid() >> 8),
( byte ) 8, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0
};
{
(byte) record.getSid(), (byte) ( record.getSid() >> 8 ),
(byte) 8, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0
};
assertEquals(expected.length, output.length);
for (int k = 0; k < expected.length; k++)
assertEquals( expected.length, output.length );
for ( int k = 0; k < expected.length; k++ )
{
assertEquals(String.valueOf(k), expected[ k ], output[ k ]);
assertEquals( String.valueOf( k ), expected[k], output[k] );
}
}
@ -473,87 +476,87 @@ public class TestSSTRecord
* @param ignored_args
*/
public static void main(String [] ignored_args)
public static void main( String[] ignored_args )
{
System.out.println("Testing hssf.record.SSTRecord functionality");
junit.textui.TestRunner.run(TestSSTRecord.class);
System.out.println( "Testing hssf.record.SSTRecord functionality" );
junit.textui.TestRunner.run( TestSSTRecord.class );
}
private byte [] readTestData(String filename)
throws IOException
private byte[] readTestData( String filename )
throws IOException
{
File file = new File(_test_file_path
+ File.separator
+ filename);
FileInputStream stream = new FileInputStream(file);
int characterCount = 0;
byte b = ( byte ) 0;
List bytes = new ArrayList();
boolean done = false;
File file = new File( _test_file_path
+ File.separator
+ filename );
FileInputStream stream = new FileInputStream( file );
int characterCount = 0;
byte b = (byte) 0;
List bytes = new ArrayList();
boolean done = false;
while (!done)
while ( !done )
{
int count = stream.read();
switch (count)
switch ( count )
{
case '0' :
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
case '8' :
case '9' :
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
b <<= 4;
b += ( byte ) (count - '0');
b += (byte) ( count - '0' );
characterCount++;
if (characterCount == 2)
if ( characterCount == 2 )
{
bytes.add(new Byte(b));
bytes.add( new Byte( b ) );
characterCount = 0;
b = ( byte ) 0;
b = (byte) 0;
}
break;
case 'A' :
case 'B' :
case 'C' :
case 'D' :
case 'E' :
case 'F' :
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
b <<= 4;
b += ( byte ) (count + 10 - 'A');
b += (byte) ( count + 10 - 'A' );
characterCount++;
if (characterCount == 2)
if ( characterCount == 2 )
{
bytes.add(new Byte(b));
bytes.add( new Byte( b ) );
characterCount = 0;
b = ( byte ) 0;
b = (byte) 0;
}
break;
case 'a' :
case 'b' :
case 'c' :
case 'd' :
case 'e' :
case 'f' :
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
b <<= 4;
b += ( byte ) (count + 10 - 'a');
b += (byte) ( count + 10 - 'a' );
characterCount++;
if (characterCount == 2)
if ( characterCount == 2 )
{
bytes.add(new Byte(b));
bytes.add( new Byte( b ) );
characterCount = 0;
b = ( byte ) 0;
b = (byte) 0;
}
break;
case -1 :
case -1:
done = true;
break;
@ -562,13 +565,55 @@ public class TestSSTRecord
}
}
stream.close();
Byte[] polished = ( Byte [] ) bytes.toArray(new Byte[ 0 ]);
byte[] rval = new byte[ polished.length ];
Byte[] polished = (Byte[]) bytes.toArray( new Byte[0] );
byte[] rval = new byte[polished.length];
for (int j = 0; j < polished.length; j++)
for ( int j = 0; j < polished.length; j++ )
{
rval[ j ] = polished[ j ].byteValue();
rval[j] = polished[j].byteValue();
}
return rval;
}
/**
* Tests that workbooks with rich text that duplicates a non rich text cell can be read and written.
*/
public void testReadWriteDuplicatedRichText1()
throws Exception
{
File file = new File( _test_file_path + File.separator + "duprich1.xls" );
InputStream stream = new FileInputStream(file);
HSSFWorkbook wb = new HSSFWorkbook(stream);
stream.close();
HSSFSheet sheet = wb.getSheetAt(1);
assertEquals("01/05 (Wed) ", sheet.getRow(0).getCell((short)8).getStringCellValue());
assertEquals("01/05 (Wed)", sheet.getRow(1).getCell((short)8).getStringCellValue());
file = File.createTempFile("testout", "xls");
FileOutputStream outStream = new FileOutputStream(file);
wb.write(outStream);
outStream.close();
file.delete();
// test the second file.
file = new File( _test_file_path + File.separator + "duprich2.xls" );
stream = new FileInputStream(file);
wb = new HSSFWorkbook(stream);
stream.close();
sheet = wb.getSheetAt(0);
int row = 0;
assertEquals("Testing ", sheet.getRow(row++).getCell((short)0).getStringCellValue());
assertEquals("rich", sheet.getRow(row++).getCell((short)0).getStringCellValue());
assertEquals("text", sheet.getRow(row++).getCell((short)0).getStringCellValue());
assertEquals("strings", sheet.getRow(row++).getCell((short)0).getStringCellValue());
assertEquals("Testing ", sheet.getRow(row++).getCell((short)0).getStringCellValue());
assertEquals("Testing", sheet.getRow(row++).getCell((short)0).getStringCellValue());
// file = new File("/tryme.xls");
file = File.createTempFile("testout", ".xls");
outStream = new FileOutputStream(file);
wb.write(outStream);
outStream.close();
file.delete();
}
}

View File

@ -55,7 +55,10 @@
package org.apache.poi.hssf.usermodel;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.RowRecord;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
* Test HSSFRow is okay.
@ -87,33 +90,47 @@ public class TestHSSFRow
assertEquals(1, row.getFirstCellNum());
assertEquals(2, row.getLastCellNum());
RowRecord rowRecord = new RowRecord();
rowRecord.setFirstCol((short) 2);
rowRecord.setLastCol((short) 5);
row = new HSSFRow(workbook.getWorkbook(), sheet.getSheet(), rowRecord);
assertEquals(2, row.getFirstCellNum());
assertEquals(5, row.getLastCellNum());
}
public void testRemoveCell()
throws Exception
{
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow row = sheet.createRow((short) 0);
assertEquals(-1, row.getLastCellNum());
assertEquals(-1, row.getFirstCellNum());
row.createCell((short)1);
row.createCell((short) 1);
assertEquals(1, row.getLastCellNum());
assertEquals(1, row.getFirstCellNum());
row.createCell((short)3);
row.createCell((short) 3);
assertEquals(3, row.getLastCellNum());
assertEquals(1, row.getFirstCellNum());
row.removeCell(row.getCell((short)3));
row.removeCell(row.getCell((short) 3));
assertEquals(1, row.getLastCellNum());
assertEquals(1, row.getFirstCellNum());
row.removeCell(row.getCell((short)1));
row.removeCell(row.getCell((short) 1));
assertEquals(-1, row.getLastCellNum());
assertEquals(-1, row.getFirstCellNum());
// check the row record actually writes it out as 0's
byte[] data = new byte[100];
row.getRowRecord().serialize(0, data);
assertEquals(0, data[6]);
assertEquals(0, data[8]);
File file = File.createTempFile("XXX", "XLS");
FileOutputStream stream = new FileOutputStream(file);
workbook.write(stream);
stream.close();
FileInputStream inputStream = new FileInputStream(file);
workbook = new HSSFWorkbook(inputStream);
sheet = workbook.getSheetAt(0);
stream.close();
file.delete();
assertEquals(-1, sheet.getRow((short) 0).getLastCellNum());
assertEquals(-1, sheet.getRow((short) 0).getFirstCellNum());
}
}

View File

@ -58,7 +58,6 @@ import junit.framework.TestCase;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WSBoolRecord;
import org.apache.poi.hssf.dev.BiffViewer;
import java.io.File;
import java.io.FileInputStream;
@ -190,7 +189,14 @@ public class TestHSSFSheet
tempFile.delete();
assertNotNull(row);
assertEquals(2, row.getPhysicalNumberOfCells());
}
public void testRemoveRow()
{
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2);
sheet.removeRow(row);
}
}

View File

@ -437,6 +437,12 @@ public class TestLittleEndian
return result;
}
public void testUnsignedShort()
throws Exception
{
assertEquals(0xffff, LittleEndian.getUShort(new byte[] { (byte)0xff, (byte)0xff }, 0));
}
/**
* main method to run the unit tests
*